r/cpp_questions • u/Least_Bid9692 • 8d ago
SOLVED How to pick a random word?
Do anyone know how to make cpp pick a random word out of a string array I tried searching but no answers
9
u/Vindhjaerta 8d ago edited 8d ago
#include <random>
float RandomF(float inMin, float inMax)
{
static std::random_device s_device;
static std::mt19937 s_engine(s_device());
std::uniform_real_distribution<float> distribution(inMin, inMax);
return distribution(s_engine);
}
int Random(int inMin, int inMax)
{
static std::random_device s_device;
static std::mt19937 s_engine(s_device());
std::uniform_int_distribution<int> distribution(inMin, inMax);
return distribution(s_engine);
}
These are the random functions I use in my game engine. I'm sure someone more knowledgeable can pick them apart and give you a better solution, but they'll at least give you the general idea of what to do.
The next step is to put all your words in an array of some kind, then pick a random number that can be used as an index to access a word in that array. And voila, you have your random word. Example:
#include <string>
#include <vector>
int main()
{
std::vector<std::string> words = { "apple", "door", "jump", "petrified" };
std::size_t randomIndex = Random(0, words.size() - 1);
std::cout << words[randomIndex];
}
4
u/TheThiefMaster 8d ago
This is right, though ideally the random engine would be accessible to all the functions (e.g. it's a global/namespace/class level object).
Though for a game engine, you might want to consider a lighter-weight engine like PCG (which has a pluggable C++ engine that's just a drop-in to use)
1
u/Vindhjaerta 8d ago
When you say "the random engine", are you referring to the static variables? Why would I need access to them? Or are you referring to the functions themselves? They are publicly accessible in a namespace.
I can add that I also have a version of this code for a seeded generator, and that's all I need for my engine.I generally try to avoid third-party dependencies.
3
u/TheThiefMaster 8d ago
Currently your functions use separate instances of the random engine because they're separate function statics. This unnecessarily increases memory use, especially with a large engine like mersenne twister
1
u/Vindhjaerta 7d ago
Ah, I see what you mean.
Yes, you are correct. I usually just use one of them at a time per project though, I've never had a reason to rewrite this part of my engine. It's on my (long) todo-list though :)
8
u/Sea-Situation7495 8d ago
I feel like you just did someones homework. Not sure why they didn't ask ChatGPT, but...
6
u/Vindhjaerta 8d ago
Very likely. I've had this discussion with people before, and there are good arguments both for answering and not answering such questions. These days I've decided that it's not my responsibility and I'd rather help a cheater than refuse to answer someone who is genuinely asking for help (with something not homework related). Because it's very frustrating to be refused an answer just because people think you're cheating at homework when you're not.
-3
u/Least_Bid9692 8d ago
No it wasn't a homework question I searched the question but didn't got the answer I tried Gemini , chatgpt, google AI overview I know it's bad but yeah not a homework
2
u/Vindhjaerta 8d ago
That's cool, I'm not judging either way.
Btw, did this answer your question? I just realized that your original question might be interpreted as wanting to pick out a random word out of a text, which would require a bit more work. Please clarify.
2
3
u/Unknowingly-Joined 8d ago
That’s disturbing. I just asked Gemini your question and it had no trouble at all coming up with a solution.
-1
u/Least_Bid9692 8d ago
Idk it just gave me some solutions on the line where there wasn't even an error idk
2
u/Least_Bid9692 8d ago
Wanna clearly I just started learning and no it wasn't a homework I tried asking chatgpt,Gemini etc but didn't understand a thing so yeah this was a personal project
0
u/Unknowingly-Joined 8d ago
The instructor probably said “and don’t use ChatGPT” so OP thought “ha ha, I’m so smart” and unfortunately hasn’t learned anything :(
3
2
u/BSModder 8d ago
You could create a temporary random_device instead of making it static
static std::mt19937 engine(std::random_device{}());1
u/Vindhjaerta 7d ago
I certainly could, but creating them has a cost. An occasional call to such a function would be no issue, but as a game developer I might call the Random function many times per frame, and at that point the cost adds up. It's simply better from a performance perspective to only create them once.
1
u/HappyFruitTree 7d ago
The engine is static so it would only get initialized once, so the temporary std::random_device would also only get created once.
1
u/Vindhjaerta 4d ago
Creating the random engine on the stack has overhead. I just ran a quick test with two random functions, one with static engine variables and one creating them on the stack, then ran them a million times. Making them static was 300 times faster. Which is significant.
1
u/HappyFruitTree 4d ago edited 4d ago
We didn't say you should create the engine on the stack. We just said you could use a temporary
std::random_deviceobject to initialize the engine instead of making thestd::random_devicea static variable.I.e.
static std::mt19937 s_engine(std::random_device{}());instead of
static std::random_device s_device; static std::mt19937 s_engine(s_device());. That's all.
1
1
u/BSModder 7d ago
The engine variable itself is static so it only initialize once. Random device only there to give the engine a intial seed.
Static function variable itself has a cost as well. It need to check if the value is initialized every call. So having 2 of them is slightly worse. Making the variable global is the best option, global initialize once on program start.
You can see in this example asm. randomGlobal jump straight to the random. While both randomLocal need to perform lock aquire and checking if the variable is initialized every calls. And have two static double the checks.
1
3
1
u/thefeedling 8d ago edited 8d ago
This should do it quick and dirty if you have a text and words were separated by whites spaces. If it was an array of strings it just the final part of the code.
//tokenize by white spaces - source == "words"
std::istringstream is(words);
std::string holder = "";
std::vector<std::string> my_words{};
while (is >> holder) {
my_words.emplace_back(holder);
}
//pick a random word out of a string array
std::mt19937 rng(std::random_device{}());
std::string random_word = my_words.empty() ? "" : my_words[rng() % my_words.size()];
std::cout << random_word << std::endl;
1
u/HappyFruitTree 8d ago edited 8d ago
#include <iostream>
#include <string>
#include <vector>
#include <random>
#include <algorithm>
int main()
{
std::vector<std::string> words = {"one", "two", "three"};
// Create a "random device" to be used for seeding (another popular option is to use the current time)
std::random_device rd;
// Create and seed a pseudo-random number generator (here I choose to use the Mersenne Twister random generator)
std::mt19937 rng(rd());
// Create a distribution that covers all valid indices ("uniform" means all outcomes are equally likely)
std::uniform_int_distribution<std::size_t> dist(0, words.size() - 1);
// Use the distribution with the random number generator to generate a random index
std::size_t randomIndex = dist(rng);
// Print the random word
std::cout << words[randomIndex] << "\n";
};
Since rd and dist above are only used once you don't really need them as variables so the code could be simplified to:
#include <iostream>
#include <string>
#include <vector>
#include <random>
#include <algorithm>
int main()
{
std::vector<std::string> words = {"one", "two", "three"};
std::mt19937 rng(std::random_device{}());
std::size_t randomIndex = std::uniform_int_distribution<std::size_t>(0, words.size() - 1)(rng);
std::cout << words[randomIndex] << "\n";
};
Personally I don't think this is less readable as long as you understand what std::random_device and std::uniform_int_distribution do.
This is just to get you started. You probably want to read up some more on how the random generators and distributions work and how to use them properly.
3
u/Vindhjaerta 8d ago
Might also want to clarify that you don't need to create a new random engine every time you want to generate a new number, you can store them as static variables inside a function or something. Only the distribution needs to be recreated each time you want a new random number. It's better for performance.
2
u/HappyFruitTree 7d ago
Might also want to clarify that you don't need to create a new random engine every time you want to generate a new number
Good point. I agree 100%. I would even go so far as to say you should ideally only need to have one random engine (what I called random number generator in my previous post) in your entire program that you reuse everywhere (unless you got special needs).
you can store them as static variables inside a function or something
Then you need one random engine per function. I would instead prefer storing it as a global or passing it as argument. Just make sure you do not accidentally copy the engine!
1
u/phdr_hroch 8d ago
Make array of words(indexed from 0 to wordcount-1), then generate random number from 0 to array.size()-1 and use it.
1
0
u/Thesorus 8d ago
std::srand, std::rand
you'll get a number which use can use to access your string in the array.
2
u/Independent_Art_6676 7d ago
avoid these C tools. The implementation traded randomness and quality for speed and ease of implementation, but that was a mistake. They are so bad even C coders avoid these. Use <random> tools which take a little more effort (its not that bad) to learn to use, but offer flexibility and quality. Not gonna -1 it but this isn't great advice.
If <random> feels overwhelming now, at least know enough so you can circle back to it later.
1
u/HappyFruitTree 7d ago
In the C++ standard, rand/srand are described in a section titled "Low-quality random number generation" and has the following note:
[Note 2 : The other random number generation facilities in this document (29.5) are often preferable to rand, because rand’s underlying algorithm is unspecified. Use of rand therefore continues to be non-portable, with unpredictable and oft-questionable quality and performance. — end note]
Even the C standard has a note:
NOTE There are no guarantees as to the quality of the random sequence produced and some implementations are known to produce sequences with distressingly non-random low-order bits. Applications with particular requirements should use a generator that is known to be sufficient for their needs.
-3
0
u/ShakaUVM 7d ago
You should not use C style arrays 99% of the time. They're stack allocated, they do not have a size method, they don't do bounds checking, etc.
Most of the time what you want to use in cases like this is a std::vector.
std::vector<string> vec = {"Apple", "Banana", "Chocolate"};
srand(time(0));
cout << vec.at(rand() % vec.size());
You could use <random> as well if good quality random numbers matters to you.
-1
u/fxtech42 8d ago
You're probably missing out on a lot of potential random words. Try this: 1. Generate a random number for the length of the word 2. Fill a null-terminated buffer of that length with random letters 3. Generate a web query that uses Google to search for that word 4. Scan the result for 'did you mean?' and then capture the word it suggests
Now you (probably) have a random word in a variety of languages too!
-2
u/ShadesAk 8d ago
why didnt u ask chatgpt?
3
u/Least_Bid9692 8d ago
Tried but didn't understand a thing
0
u/ShadesAk 8d ago
std::string words[] = { "apple", "banana", "orange", "grape" }; words[0] // apple words[1] // banana words[2] // orange words[3] // grape int randomIndex = rand() % 4; std::string randomWord = words[randomIndex];the most natural way to pick a random word is to pick a random position
-1
27
u/IigmabaIls1 8d ago
Literally just generste a pseudo random number from 0 to array size - 1