How to scramble a word using rand

I'm trying to randomly scramble a word as part of an assignment I'm doing for my final exam. I just don't know if there's a certain function which involves rand or if I should try to pull some array magic.

As of right now, my code is successfully getting the word and I'm waiting on finishing all checks of guesses before I get too far along.

Where this needs to go is somewhere after the word/length is gotten but before my while loop, which was just for testing if my input and related is in working order.

// Here's my code at the moment //

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
#include <ctime>

using namespace std;

const int NUM_WORDS = 60;

int main()
{
    srand(time(NULL));
    
    string list[NUM_WORDS];
    int word;
    string guess;
    string entered;
    int guesses = 0;
    
    ifstream in;
    in.open("wordlist.txt");
    
    while(!in.eof())
    {
        for(int i = 0; i < NUM_WORDS; i++)
        {
            in >> list[i];
        }
    }
    
    word = rand() % 60;
    
    guess = list[word];
    cout << "Your code is " << guess.length() << " characters long" << endl;
    
    cout << "Please make your guess or enter # to stop: ";
    cin >> entered;
    
    while(entered != "#")
    {
        while(entered.length() != guess.length())
        {
            cout << "The guess must be the same number of characters as your code word." << endl;
            cout << "Your code is " << guess.length() << " characters long" << endl;
            cout << "Please make your guess or enter # to stop: ";
            cin >> entered;
        }
        
        guesses++;
        cout << "You have guessed " << guesses << " times" << endl;
        cout << "You entered " << entered << endl;
        cout << "Your code is " << guess.length() << " characters long" << endl;
        cout << "Please make your guess or enter # to stop: ";
        cin >> entered;

    }
    
    
    
    
    
    return 0;
} 


// Here is the file the word is gotten from //

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
pit
jet
ban
far
pop
bite
navy
yard
curl
head
bang
soup
tail
test
pull
dine
game
sock
load
goat
clock
tower
cower
white
medal
bland
staff
robot
spoil
chaos
ratio
style
shame
shift
rider
agent
night
wheel
spine
right
polite
insert
hotdog
reduce
vessel
reveal
garage
cotton
realism
archive
abolish
profile
economy
command
comment
extract
revival
regular
scandal
dribble
Do you mean somthing like this perhaps?

http://www.cplusplus.com/reference/algorithm/random_shuffle/

See the example. Particularly line 22. You can use string instead of the std::vector<int> the same way.
Hello domweng,

I have been going over your code and even if you use coder777's suggestion of the random_shuffle it might help, but in the end your use of "rand" may be the bigger problem. But if you do a shuffle before each new word is picked it may make a difference based on what you get from "rand".

To start with in "main" srand(static_cast<unsigned int>(time(nullptr))); is the more up-to-date way of using "srand". A good video that talks about the problems with "rand" is at https://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful

This is what I ended up with for your variables:
1
2
3
4
5
//int word{};  // <--- ALWAYS initialize all your variables.
int wordCountIdx{};
string guess;
string entered;
string list[NUM_WORDS];

Eventually I found that line 1 is not needed.

You define a file stream and then open the file, but never check that it is open and usable. This may be more than it needs to be, but I found it useful in the beginning when working with files:
1
2
3
4
5
6
7
8
9
10
11
12
const std::string inFileName{ "wordlist.txt" };  // <--- Put File name here.

std::ifstream inFile(inFileName);

if (!inFile)
{
    //std::cout << "\n     File " << std::quoted(inFileName) << " did not open.\n";  // <--- Requires header file "<iomanip>".
    std::cout << "\n     File \"" << inFileName << "\" did not open.\n";

    return 1;
    //return (std::cout << "\n     File \"" << inFileName << "\" did not open.\n"), 1;
}

The commented return can shorten this to just 1 line when you are ready.

The while loop and for loop for reading the file. I have to ask if you could find a more difficult way of doing this? As is it is not the best way to read a file. Either use a while loop or a for loop, but not both. Reading the file can be shortened to 1 line: while (wordCountIdx < NUM_WORDS && inFile >> list[wordCountIdx]) wordCountIdx++;. This way if there are more than 60 words in the file it will limit it to 60 and if there are less than 60 words the rhs will cause the condition to be false when it sets the "eof" bit on the stream. Either way "wordCountIdx" will have the correct number of words read from the file.

As you can see this can be condensed into 1 line:
1
2
3
4
//word = rand() % wordCountIdx;

//guess = list[word];
guess = list[rand() % wordCountIdx];

I used "wordCountIdx" here because it could be 60 or it could be less. It is based on how many words were read from the file.

After this the code needs reworking.

Starting with what was word = rand() % wordCountIdx; I put this line down to the closing } of the original while (entered != "#") in a do/while loop because there was no way to get back to picking a new word.

After the opening { of the do/while I put int guesses{ 1 }; here. This way at the closing } of the do/while this variable is destroyed and if you loop back to the beginning it is remade and set to (0)zero for the next word.

For the original while loop I did this. It could be cleaned up a bit:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
while (entered != "#")
{
    if (entered.length() != guess.length())
    {
        cout <<
            "\n"
            " The guess must be the same number of characters as your code word.\n"
            " Your code is " << guess.length() << " characters long\n\n";
            //" Please make your guess or enter # to stop: ";
        //cin >> entered;
    }

    else if (entered == guess)
    {
        cout <<
            "\n"
            " You have guessed " << guesses << " times\n"
            " You entered " << entered << "\n"
            "  You have guessed correctly! Good job.\n\n";
            //" Please make your guess or enter # to stop: ";
        break;
        //cin >> entered;
    }
    else
    {
        std::cout <<
            "\n     Incorrect guess!\n\n";
        //cin >> entered;
    }

    std::cout << " Please make your guess or enter # to stop: ";
    std::getline(std::cin, entered);

    guesses++;
}

In your original code the while loop on line 3 is not the best way. The if statement works better along with the else if and else.

The redundant code was commented out and moved to after the else.

When you get a match, or correct guess, you need to break out of the while loop to get to the do/while and start over picking a new word.

Should you enter a (#) it will leave both loops and the program will end normally.

I played with this function to use a more up-to-dare C++ way to generate a random number. It requires the header file "<random>" to use it:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int GetRandomNum(int wordCountIdx)
{
    const int range_from{};  // <--- Initializes to (0)zero.
    const int range_to{ wordCountIdx };

    std::random_device rand_dev;

    std::mt19937 generator(rand_dev());

    std::uniform_int_distribution<int>  distr(range_from, range_to);

    //std::cout << distr(generator) << '\n';

    return distr(generator);
}

Originally the function takes no parameters and "range_to is hard coaded in the function. I changed this part to use the value of "wordCountidx". You can use it if you want or "rand" does work.

Andy
Topic archived. No new replies allowed.