So I'm working on developing an online game, and one of the features of this game (like many other MMORPG's) is the drop system & upgrade system.
The drop system decides what items will drop from monsters when they are killed.
The upgrade system decides if an item will successfully upgrade to the next level or not.
They both need to be able to use probability to determine if:
An item Drops
An item upgrades successfully.
I've developed a system that generates a random number between 0 and 100000. In this system a 1% probability of either of the above happening would be represented by 1000. Similarly, a 0.5% would be 500... and 50% would be 50000.
Here is the guts of this code...
int RandomValueInRange(const int start, const int end)
{
std::random_device rd;
std::mt19937 generator(rd());
const int stable_end = ((end < start) ? start : end);
std::uniform_int_distribution<int> distribution(start, stable_end);
return distribution(generator);
}
Now in order to dermine if an item drops or upgrades sucecsfully, all I have to do is this...
const int random_value = RandomValueInRange(0, 100000);
const int probability = item.GetProbability();//This simply returns an integer stored in a config file which represents the probability of this item being dropped/upgraded.
if(random_value <= probability)
{
std::cout << "Probability Success!" << endl;
}
else
{
std::cout << "Probability Failed!" << endl;
}
I would expect the above to work, but for whatever reason it seems faulty... Players are able to get items that have a 0.1% probability with ease (something that should almost never happen!).
Does anyone know of a better system or how I can improve this system to truly follow the probability guidelines....
std::random_device rd;
std::mt19937 generator(rd());
...
return distribution(generator);
I think problem here, the std c++ library gives you uniform distribution
if you do reuse random_device and mt19937, but you recreate them each time,
it is not how that they should be used.
Save somewhere this std::random_device rd and this std::mt19937and this distribution
Ok, so the problem with your code is that you are choosing a random number between 0 and 100,000. Anyone can get between 1 and 100 with a bit of luck, because, if you think about it, 100 is a pretty big number and shouldn't be too hard to get.
Also, if you go back to Primary/Elementary (or whatever you want to call it) school maths books, you will see in the 'probability and chance' chapter, some questions like:
If there are 6 balls in a bag, 3 red, 1 green and 2 blue, then what is the chance of choosing a blue?
Of course, you would've answered 2/6 or 1/3. In C++, this can be changed to something like this:
#include <iostream>
#include <ctime>
#include <algorithm>
#include <random>
using namespace std;
// Be sure to have this in to get a truly random number
class MoreProbability {
// Be sure to have this in to get a truly random number
void GetProbability(int min, int max, int probability) {
const int arrayMax = max;
int probabilityArray[100000];
for (int i = 0; i < max; i++) {
if (i >= 0 && i <= probability) {
probabilityArray[i] = 1;
}
else {
probabilityArray[i] = 0;
}
}
// Arrays go from 0 to max-1 to account for the 0
std::random_shuffle(&probabilityArray[0], &probabilityArray[max - 1]);
// Check if the first element of the randomly shufffled array is equal to 1
if (probabilityArray[0] == 1) {
cout << "Probability Successful" << endl;
}
else {
cout << "Probability Failed" << endl;
}
}
int main() {
srand(time(0));
GetProbability(0, 100000, 100);
return 0;
}
};
It may give a StackOverflowException. To fix this, simply increase the 'Stack Reserve Size'.
EDIT:
After changing the code around a bit to return a 1 or a 0 based on the outcome, and putting it into a for loop which repeated itself 1000 times (I do NOT recommend trying this as it takes a while to complete), I got an output of 1, clearly showing that this piece of code works perfectly.
Related
I have an array with 7 elements and I'm trying to get a random number between 0 - 6 so I can select an element in the array at random.
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
class Color{
public:
Color(){
colors[0] = "red";
colors[1] = "orange";
colors[2] = "yellow";
colors[3] = "green";
colors[4] = "blue";
colors[5] = "indigo";
colors[6] = "violet";
}
void printColors()
{
for (int i = 0; i<sizeof(colors)/sizeof(colors[0]); ++i)
{
cout << colors[i] << endl;
}
}
void printRandomColor()
{
int random_integer = rand() % 7;
cout << random_integer << endl;
}
private:
string colors[7];
};
int main(int argc, const char * argv[]) {
srand( static_cast<unsigned int>(time(0)));
Color colorObject;
colorObject.printRandomColor();
return 0;
}
When I do rand() % 7 I keep getting 6, but if I do rand() % 6 I end up getting random numbers. What gives?
I call srand( static_cast<unsigned int>(time(0))); in my main()
I noticed the same behavior with the code shown in the question:
rand() % 7 // always shows 6
rand() % 14 // always shows 6 or 13
rand() % 21 // always shows 6, 13, or 20
The problem is peculiar and there seems to be a pattern involved. Based on the comments that some aren't able to reproduce it, I decided to compile the code, with gcc on a Linux based machine and clang on macOS; Linux seems to behave normally from what I can tell, however macOS does not. I even tried completely different code just make sure it wasn't something else, yet got the same result.
#include <cstdlib>
#include <iostream>
#include <ctime>
int main()
{
int min = 1;
int max = 7;
std::srand(std::time(0)); // use current time as seed for random generator
// int random_variable = std::rand() % max; // always returns 6
// int random_variable = std::rand() % (max - min) + min; // produces 'predictable' numbers based on the time.
int random_variable = RAND_MAX % std::rand() % (max-min) + min; // also returns predicate results based on the timing, except in reverse.
std::cout << "Random value on [0 " << RAND_MAX << "]: "
<< random_variable << '\n';
}
The only way I was able to get seemingly random results from rand() was to do:
RAND_MAX % std::rand() % (max-min) + min; // predictable based on timing
The issue is odd, and might be a bug with Clang; I'm at a loss at to what exactly is at play here. I would probably recommend using something other than rand() such as the <random> library mentioned in the comments perhaps.
EDIT: After reporting this bug to Apple this was the response:
Apple Developer Relations July 27 2017, 11:27 AM
There are no plans to address this based on the following:
std::rand directly uses rand from the C library. rand is known and
documented to be broken (and is not going to change since people
depend on its specific behavior).
From the man page: RAND(3) BSD Library Functions Manual
NAME
rand, rand_r, srand, sranddev -- bad random number generator
DESCRIPTION
These interfaces are obsoleted by arc4random(3).
For good pseudorandom numbers in C++, look at from C++11.
E.g.: http://en.cppreference.com/w/cpp/numeric/random
Based on this information RAND() is broken and won't be fixed — use an alternative random number generator.
rand() is terrible. rand() % range is worse. Don't use it. Use arc4random_uniform().
#include <iostream>
#include <cstdlib> // Needed for arc4random_uniform()
int main(int argc, char *argv[]) {
// Random number between 0 and 6.
std::cout << arc4random_uniform(7) << std::endl;
}
So in your case:
void printRandomColor()
{
int random_integer = arc4random_uniform(7);
cout << random_integer << endl;
}
If portability is desired, then here is a C++ standard example. To me, it's needlessly more complicated and runs slower, but hey… it's the C++ standard.
#include <iostream>
#include <random> // For std::random_device and std::uniform_int_distribution
int main() {
std::random_device randomizer;
std::uniform_int_distribution<int> distribution(0, 6);
// Random number between 0 and 6.
int random_integer = distribution(randomizer);
std::cout << random_integer << std::endl;
}
I would like to point out, that you are using a Random (Rand) operator, then trying to find out if the result has a Remainder (%), the Result will be the Remainder, which is where your strange math comes from. This is known as the Modulo Operator or Modulus Operator if you desire to Google it, although you should know that it actually has a slightly different name in C#, there is a Post in StackTrace about it Here:
What does the '%' operator mean?
If you open the Calc.exe Windows Program it is listed in Scientific Mode (Alt+2) as Mod.
Specifically, the way % operates is ((x - (x / y)) * y)
The above URL is a direct link to my answer where I point out specifically HOW it differs from standard / complete with a long drawn out example simulating all of the math step by step, the result returns a 0 for % and a 1 for / since the / Operand does roundUp() whilst % does roundDown() from what I've understood in the other Answers in that Post.
Update
I would at least like to have this answer here to provide reference for the Modulo Operator which is mentioned in the title of this question.
I didn't post this specifically as an answer per se, but more as reference material to avoid spam posts in the future.
If this is in fact a discovered bug, then this question is going to be picked apart letter by letter, symbol by symbol, and it's going to assist everybody involved to have this reference material here.
If I didn't know already it was named Modulo/Modulus in most languages, I would wonder what he meant by "Modulo" as he never explains anywhere that the % is named exactly that.
This answer addresses the fact that % uses roundDown() whereas / uses roundUp() complete with a referenced compile-able example written painstakingly in expanded step-by-step longhand which I then converted to C#.
I also would like to reiterate, as I mentioned in the comments, I have zero knowledge about xCode, I am somewhat familiar with C# and have provided this information in the C# context which this question is tagged with.
I'm making a program in which every time when I run the program, a random quotation is displayed. This should be done by using rand and srand. I'm making logic and searching but couldn't understand how to do it. Can someone please tell me what's wrong.
const string Quot[14] = { "1)Love Pakistan", "2)Be Honest", "3)Work Work and Work", "4)I am always doing things I cannot do.That is how I get to do them.", "5)It is not what we take up, but what we give up, that makes us rich.", "6)You can do anything, but not everything.", "7)Thinking will not overcome fear but action will. ", "8)We read the world wrong and say that it deceives us.", "9)You miss 100 percent of the shots you never take.", "10)He is the happiest, be he king or peasant, who finds peace in his home.", "11)Your work is to discover your work and then, with all your heart, to give yourself to it.", "12)In order to be effective truth must penetrate like an arrow – and that is likely to hurt", "13)You must be the change you wish to see in the world", "14)Humans are satisfied with whatever looks good; ? Heaven probes for what is good." };
for (int i = 0; i < 14; i++)
{
int choiceLen[i] = c.getLenght(Quot[i]);
const int randomLength = 1;
string randomStr[randomLength + 1];
for (int i = 0; i < randomLength; i++)
{
randomStr[i] = Quot[i][rand() % choiceLen[i]];
cout << randomStr[i] << endl;
}
}
rand is a pseudo-random number generator. That means it isn't truly random, and one of the first limitations is that - for legacy reasons based in testability - it always starts with the same seed and thus always produces the same random sequence.
In order to break this, you need to provide some entropy, a random seed. The most common way to do this is to do the following at the start of main():
srand(time(nullptr));
Caveat: If you run this twice in the same second, it will get the same random seed.
If you have C++11 available to you, you can use <random> and std::shuffle
#include <iostream>
#include <string>
#include <array>
#include <random>
#include <algorithm>
int main()
{
std::array<std::string, 3> quotes = {
"1 hello", "2 world", "3 hello world"
};
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> quoteSeed(0, quotes.size() - 1);
int quoteNo = quoteSeed(gen);
auto quote = quotes[quoteNo];
std::shuffle(quote.begin(), quote.end(), gen);
std::cout << quote << "\n";
}
Live demo: http://ideone.com/Lv1M7w
I happen to notice that in C++ the first random number being called with the std rand() method is most of the time significant smaller than the second one. Concerning the Qt implementation the first one is nearly always several magnitudes smaller.
qsrand(QTime::currentTime().msec());
qDebug() << "qt1: " << qrand();
qDebug() << "qt2: " << qrand();
srand((unsigned int) time(0));
std::cout << "std1: " << rand() << std::endl;
std::cout << "std2: " << rand() << std::endl;
output:
qt1: 7109361
qt2: 1375429742
std1: 871649082
std2: 1820164987
Is this intended, due to error in seeding or a bug?
Also while the qrand() output varies strongly the first rand() output seems to change linearly with time. Just wonder why.
I'm not sure that could be classified as a bug, but it has an explanation. Let's examine the situation:
Look at rand's implementation. You'll see it's just a calculation using the last generated value.
You're seeding using QTime::currentTime().msec(), which is by nature bounded by the small range of values 0..999, but qsrand accepts an uint variable, on the range 0..4294967295.
By combining those two factors, you have a pattern.
Just out of curiosity: try seeding with QTime::currentTime().msec() + 100000000
Now the first value will probably be bigger than the second most of the time.
I wouldn't worry too much. This "pattern" seems to happen only on the first two generated values. After that, everything seems to go back to normal.
EDIT:
To make things more clear, try running the code below. It'll compare the first two generated values to see which one is smaller, using all possible millisecond values (range: 0..999) as the seed:
int totalCalls, leftIsSmaller = 0;
for (totalCalls = 0; totalCalls < 1000; totalCalls++)
{
qsrand(totalCalls);
if (qrand() < qrand())
leftIsSmaller++;
}
qDebug() << (100.0 * leftIsSmaller) / totalCalls;
It will print 94.8, which means 94.8% of the time the first value will be smaller than the second.
Conclusion: when using the current millisecond to seed, you'll see that pattern for the first two values. I did some tests here and the pattern seems to disappear after the second value is generated. My advice: find a "good" value to call qsrand (which should obviously be called only once, at the beginning of your program). A good value should span the whole range of the uint class. Take a look at this other question for some ideas:
Recommended way to initialize srand?
Also, take a look at this:
PCG: A Family of Better Random Number Generators
Neither current Qt nor C standard run-time have a quality randomizer and your test shows. Qt seems to use C run-time for that (this is easy to check but why). If C++ 11 is available in your project, use much better and way more reliable method:
#include <random>
#include <chrono>
auto seed = std::chrono::system_clock::now().time_since_epoch().count();
std::default_random_engine generator(seed);
std::uniform_int_distribution<uint> distribution;
uint randomUint = distribution(generator);
There is good video that covers the topic. As noted by commenter user2357112 we can apply different random engines and then different distributions but for my specific use the above worked really well.
Keeping in mind that making judgments about a statistical phenomena based on a small number of samples might be misleading, I decided to run a small experiment. I run the following code:
int main()
{
int i = 0;
int j = 0;
while (i < RAND_MAX)
{
srand(time(NULL));
int r1 = rand();
int r2 = rand();
if (r1 < r2)
++j;
++i;
if (i%10000 == 0) {
printf("%g\n", (float)j / (float)i);
}
}
}
which basically printed the percentage of times the first generated number was smaller than the second. Below you see the plot of that ratio:
and as you can see it actually approaches 0.5 after less than 50 actual new seeds.
As suggested in the comment, we could modify the code to use consecutive seeds every iteration and speed up the convergence:
int main()
{
int i = 0;
int j = 0;
int t = time(NULL);
while (i < RAND_MAX)
{
srand(t);
int r1 = rand();
int r2 = rand();
if (r1 < r2)
++j;
++i;
if (i%10000 == 0) {
printf("%g\n", (float)j / (float)i);
}
++t;
}
}
This gives us:
which stays pretty close to 0.5 as well.
While rand is certainly not the best pseudo random number generator, the claim that it often generates a smaller number during the first run does not seem to be warranted.
I am extremely new to c++, and I was wondering how I might output text from a random number generator.
I am creating a text game. You occasionally fight things and I wish for whether you win or lose be random. For instance, if the random number is 2 (the only choices it would have would be one or two) then it would say: " You lost!". Please keep answers simple as I am very new and explaining your solution would be perfect.
Thanks in advance.
#include <cstdlib>
#include <iostream>
#include <ctime>
int main()
{
std::srand(std::time(0)); // use current time as seed for random generator
int random_variable = std::rand();
std::cout << "Random value on [0 " << RAND_MAX << "]: "
<< random_variable << '\n';
}
Source: http://en.cppreference.com/w/cpp/numeric/random/rand
Than, you can just compare it with your constant variable and do any action, ex.:
if (random_variable > 2)
doSomething();
else
doSomethingElse();
Since so many usages of rand have been proposed here, let's do it a bit more robust:
We will seed with std::random_device do ease into how <random> works. (You could use time(0) here, it does not really matter.)
Our actual PRNG (the thing that makes numbers) will be [std::mt19937_64](http://en.cppreference.com/w/cpp/numeric/random/mersenne_twister_engine], which is accepted as one of the better random number generators.
We will not simply inspect one bit, but tell C++ that we want a number in the range [0,1].
We will combine this into a single object that you just need to call.
A simple comparision will let us decide whether the player won or lost.
So, starting with number 1:
#include <random>
#include <functional>
#include <iostream>
int main() {
using namespace std; // because I am lazy today
random_device seeder; // call this to get a number
// more to do here
}
Now, while seeder() gives a random number, it is usually expected that you will just use this to seed your own PRNG (unless you do crypto, in which case it becomes much more complicated). So, let's do it:
mt19937_64 prng(seeder());
Well, that was easy. Now, let's make a distribution:
uniform_int_distribution<int> distribution(0, 1);
Now, to get an int that is either 0 or 1, we could just toss the prng to the distribution, as in:
int one_or_zero = distribution(prng);
But, that is cumbersome. So instead of the previous steps, we just combine everything:
auto dist = bind(uniform_int_distribution<int>(0, 1), mt19937_64(seeder()));
You can read this as "Make me a function-like variable named dist which holds a uniform distribution (every value is as likely as any other) of the range [0, 1] that is powered by an Mersenne Twister 64 PRNG.
All we now need to do is:
int one_or_zero = dist();
Ok, we just need to wrap a little if around a call to dist - sounds easy:
if(dist() == 0) {
cout << "You won!\n";
} else {
cout << "Sorry, you lost.\n";
}
You can see the result in action here, but be aware that the result is cached, so you'll need to fork it and run it yourself to see it change.
P.S.: Please note that it results in exactly two lines with the semantics similar to (swap it around a bit and you get exactly the same semantics) srand/rand -- except that it avoids a whole bunch of problems associated with those functions.
#include<iostream>
using namespace std;
int main()
{int ran_num=0;
srand((unsigned)time(0));
while(ran_num !=2) //You can add options here.
{ran_num=rand() % 100;//You can change the max number.
cout<<ran_num<<" "<<endl;
}
cout<<"You lost!";}
Since your random out has only two states, you can think about it as flipping a coin, so you can take a random function and perform a modular division by 2, like this example (just look for 'coin toss' and you will get tons of samples):
http://www.c-program-example.com/2012/05/c-program-to-toss-coin-using-random.html
int toss = rand() % 2;
you can use toss to manage your chooses.
If there are only two options, the fastest way is to be interested only in value of the least significant bit.
if(randomNumber & 1) // equals 1 if the LSB is set.
cout << "You won!" << endl;
else
cout << "You lost!" << endl;
I am trying to make a text based fighter in C++, this is one of the first things that I have done. So far I have this:
//Text Based Fighter
#include <iostream>
#include <stdlib.h> //srand, rand
#include <string>
using namespace std;
int main() {
//Player
int playerHealth = 100;
int attack1;
int attack2;
int attack3;
string attack;
int npc1;
int npc2;
cout << "Do you want to attack " << rand()[npc1,npc2];
//varname = rand() % 10 + 1;
return 0;
}
What I am wanting it to do is randomly pick between npc1 and npc2, thank you.
Also any comments on how I am writing my code would be appreciated, I have only started a couple of days ago thank you, if you need any more detail please feel free to ask, thank you.
You can just use an array of an arbitrary number of variables to choose from:
int attack[n]; //For some int-constant n
attack[rand() % n]; //choose a random attack-variable, use it
For just 2 choices you can take the remainder from 2 with a ternary expression:
int choice = rand() % 2 == 0 ? npc1 : npc2;
If you have more than 2 choices, or even if you don't, you can make an array with those and index into it.
int npc_choices[2];
int choice = npc_choices[rand() % 2];
If the number of choices is not a power of 2 you will likely introduce a very small bias into the selection with the modulo % operator. If you're not working on anything with statistical significance or with a huge number of choices I wouldn't worry about it.
It’s easy to make mistakes when generating pseudo-random numbers. For example, in some cases using rand() % RANGE can lead to a subtly-wrong distribution of numbers. (See this reference for examples of the problem.)
This may not matter if what you are doing is trivial.
If you want high-quality pseudo-random numbers, there are ways to fix rand() (see above reference), but modern C++ also provides <random> and uniform_int_distribution.
Here’s an example, simulating throwing a 6-sided die, adapted from examples in Boost and the C++ Reference:
#include <iostream>
#include <random>
std::random_device rd;
std::mt19937 gen(rd());
int roll_die() {
std::uniform_int_distribution<> dist(1, 6);
return dist(gen);
}
int main() {
std::cout << roll_die() << std::endl;
}
The part that says dist(1, 6) could be changed to dist(0, 1) to produce output in the range [0, 1] (inclusive) with a uniform distribution.
If you have just two choices in C++11 you can use std::bernoulli_distribution and here is an overly simplified sample:
#include <iostream>
#include <random>
int main()
{
std::random_device rd;
std::mt19937 gen(rd());
// give "true"1/2 of the time
// give "false" 1/2 of the time
std::bernoulli_distribution d(0.5);
int npcs[2] = {100, 101};
int index = d(gen) ? 0 : 1;
std::cout << "Do you want to attack " << npcs[index] ;
}
using an array is more flexible since it expands easily to more than two choices and then you would need to use std::uniform_int_distribution to choose between [0,N].
In the long run using rand() is not a good idea, although in many simple cases it may work fine. As Pete mentions as long you understand the limitations of rand() you can use it and the C FAQ has a good section on it, How can I get random integers in a certain range?.