How to use a Random number Generator in C#? - c#

I created a Windows Forms application using Visual Studio Professional in C#. In my program I prompt the user to input the number of rolls he/she wants and then they press enter to get the numbers.
The numbers are shown in the same form under a label and get tallied up. I know how to tally the numbers know but I can't get the random number generator to generate the number of rolls the user inputs.
This is what i am doing:
Random randGen = new Random;
int oneRoll = randGen.Next(1,7) + randGen(1, 7);
I want the same program to occur the number of times the user wants. I tried a for loop but couldn't get what I wanted.

Make sure you create the Random Number generator just once.
Do NOT create it in each loop iteration.
Or, the numbers may not be random because the loop is so tight it will use the same time as the seed in the internal generator.

Try something like this:
Random randGen = new Random();
var rolls = new List<int>();
int sum = 0;
for (int i = 0; i < numberOfRolls; i++)
{
int randomNum1 = randGen.Next(1,7);
int randomNum2 = randGen.Next(1,7);
sum += randomNum1 + randomNum2;
rolls.Add(randomNum1);
rolls.Add(randomNum2);
}
Now all the separate rolls are in rolls, and the sum of them has already been calculated.
Edited to roll two dice, record them individually, and sum it all together.

int rolls = Console.ReadLine();
int total = 0;
Random randGen = new Random(System.DateTime.Now.Millisecond);
for(int i =0; i<rolls; i++)
{
int oneRoll = randGen.Next(1,7) + randGen.Next(1, 7);
Console.WriteLine("Rolled " + oneRoll);
total += oneRoll;
}
Console.WriteLine("Total " + total);
NB. you don't need the Millisecond bit, the seed just makes it more random

Your code is totally wrong...
Random randGen = new Random(DateTime.Now.Ticks); // unique seed, mostly
int result = 0;
for (int i = 0; i < number_of_rolls_the_user_wants; i++)
result += randGen.Next(2, 14); // (1 - 7) + (1 - 7) = 2 - 14 lol... >.>
Replace number_of_rolls_the_user_wants with the number of rolls the user wants.
result will hold the result.
Also please note that, if you generate many random numbers in a short time, use the same Random object!

Related

Dividing 100 evenly by a dynamic variable

I am assigning employees a random integer percentage of 100. This percentage is based on how many employees we have and must total to 100.
If we have 4 employees, I would perhaps want to generate a split such as 80-10-5-5.. if we had 2 employees. The more random the percentages are, the better.
I'm not sure how to accomplish this elegantly without a ton of different if statements but even then the randomness would be limited I feel.
Just assign each employee a random number in a certain range (range ist up to you). Than calculate the sum of the random numbers. Last step: devide each random number by the sum which gives you the percentage.
Example: random number 3, 9, 7
Sum = 19
Percentages: 3/19=16%, 9/19=47%, 7/19=37%
(Values are rounded.)
I have written a sample code for this:
int no_of_employees = 4;
int total_percentage = 100;
List<int> tempNumberList = new List<int>();
List<int> finalNumberList = new List<int>();
Random random = new Random();
for (int i = 0; i < no_of_employees; i++)
{
tempNumberList.Add(random.Next(total_percentage));
}
int sum = tempNumberList.Sum();
foreach(int number in tempNumberList)
{
finalNumberList.Add((number * total_percentage) / sum);
}
if(finalNumberList.Sum() != total_percentage)
{
finalNumberList[0] = finalNumberList[0] + (total_percentage - finalNumberList.Sum());
}
Please feel free to improve the logic if necessary at all.
This should work:
var random = new Random();
var percentages = new List<int>();
int remainder = 100;
for (int i = 0; i < employeesCount; i++)
{
int percentage = random.Next(remainder);
percentages.Add(percentage);
remainder -= percentage;
}
percentages[percentages.Count - 1] += remainder;
Note that
the last line solves the rounding issue in case the percentages' sum is not 100
a solution using only LINQ is also doable although less readable and probably with an impact on performance (using Aggregate for instance introduces the creation of an anonymous type)
I'm not 100% sure this solution guarantees equal probability (especially the last employee's case)

Having trouble getting looping to get an accurate average WITHOUT using Math.Sqrt. Ideas?

So my professor wants us to make a program that takes in a number than spit out the square root for it. The catch is we aren't allowed to use Math.Sqrt or else there will be a 50% score penalty. So instead I'm using the following method from here...
Guess a number for the sqrt.
Divide the number by the guess.
Average the original guess and the new guess.
Make this average the current guess, and revert to step 2.
The thinking is once you do it 3-4 times (or more?) it should get closer, and closer to the actual sqrt.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void calculateSqr_Click(object sender, RoutedEventArgs e)
{
decimal wantedSqrt = Decimal.Parse(input.Text); //Takes the number from the textbox, and converts it to an int.
Random rnd = new Random(); //We're going to pick a random number.
decimal guess = rnd.Next(1, 100); //Pick a number between 1-100.
for (int i = 0; i <10; i++)
{
decimal divHolder = wantedSqrt / guess; //Divide.
decimal avgVal = (guess + divHolder) / 2; //Average.
avgVal = guess; //Make the average our new guess.
Console.WriteLine(guess); //Seems like all it does is write the number 10 times.
}
string wantedSqrtString = wantedSqrt.ToString();
MessageBox.Show(wantedSqrtString);
}
}
As you can tell the issue is in my for loop. I thought that it would work so that it takes the wantedSqrt, dive it, average it with the guess, and then the new average would become the guess, and it would loop. Instead it just repeats the number 10 times in the output. What is going wrong here?
I fixed your code here:
decimal wantedSqrt = Decimal.Parse(input.text); //Takes the number from the textbox, and converts it to an int.
Random rnd = new Random(); //We're going to pick a random number.
decimal guess = rnd.Next(1, 100); //Pick a number between 1-100.
for (int i = 0; i <10; i++)
{
decimal divHolder = wantedSqrt / guess; //Divide.
guess = (guess + divHolder) / 2; //Average.
//Make the average our new guess.
Console.WriteLine(guess); //Seems like all it does is write the number 10 times.
}
string wantedSqrtString = wantedSqrt.ToString();
Console.WriteLine(wantedSqrtString);

c# unique random number

i'm trying to get X number of random number (where X is a variable) between 0 and 100 and add them to a row in a DataGridView. I'm using the code below, but the problem is i need it to be impossible to have the same number twice. Is there a way make sure i get unique random numbers?
int X = 20;
Random random = new Random();
int randomrow = random.Next(0, 100);
for (int i = 0; i < X; i++)
{
int randomNumber = random.Next(0, 100);
data.Rows[randomrow][3] = randomNumber;
}
Thanks for the help!
Split your problem in two:
Create a list of X random, unique numbers. There are numerous ways to do that:
a. Create a list of all numbers 0-100 and then shuffle them. OR
b. Keep a hash set of all the numbers you already created (in addition to the list) and only add a new one if it has not been added before.
Afterwards, loop through the list and the data rows simultaneously and insert the values into the rows.
Here's the simple way to do it without creating a shuffle method for the List (though there are examples of that). Basically create a list of all possible integers, populate the list, then sort by new GUIDs.
int X = 20;
var RowNumbers = new List<int>();
for (int i = 0; i < X; i++)
RowNumbers.Add(i);
foreach (int i in RowNumbers.OrderBy(f => Guid.NewGuid()))
{
data.Rows[i][3] = i;
}
You would need to compare the numbers you have already used to the next one you get from random.Next. If you have already used it, pick another. I also like Heinzi's answer.
Here is algorithm without shuffling and previous result using:
var max = 100; // max available value
var count = 20; // number of random numbers
var random = new Random();
var rest = (double)max;
for (int i = 0; i < max; i++, rest--)
{
if (count / rest > random.NextDouble())
{
Console.WriteLine(i); // here is your random value
count--;
if (count == 0)
{
break;
}
}
}

C# Code only works when using the debugger? [duplicate]

This question already has answers here:
Random number generator only generating one random number
(15 answers)
Closed 7 years ago.
So here's the code I've been using. Its just a simple program to test to see if 3 randomly generated numbers are in ascending or descending order. For some reason if I'm using the debugger and stepping into every line then the code works properly. If not then it says the numbers are in order 100% or out of order 100%, which should not be the case.
Here is the code I've been using:
int num1;
int num2;
int num3;
int yes = 0;
int no = 0;
for (int i = 0; i <= 99; i++)
{
Random rnd = new Random();
num1 = rnd.Next(1, 11);
num2 = rnd.Next(1, 11);
num3 = rnd.Next(1, 11);
if ( ((num1 <= num2) && (num2 <= num3)) || ((num1 >= num2) && (num2 >= num3)) )
{
yes += 1;
}
else
{
no += 1;
}
}
Console.WriteLine("The Number are in ascending order " + yes.ToString() + " Times");
Console.WriteLine("The Number are not in ascending order " + no.ToString() + " Times");
Console.ReadLine();
I think that it might be a problem with the pseudo random and the code generating the same 3 numbers every time, but I'm still learning more about programming and other help would be greatly appreciated.
The new Random() constructor uses the current time as the seed.
Unless you wait in the debugger, all of your Random instances have the same seed.
You should use a single instance.
This has to do with how the random numbers are generated.
If you take
Random rnd = new Random();
and move it out of the loop, you should see the desired results.
More background:
The random number generator uses a seed based on the time you instantiate it. Because your code is running so quickly, the seed is the same so the numbers are the same. This is why it works when you step through.
Instantiating the Random outside of the loop will instantiate it once and use the random algorithm to generate new numbers.

Why am I getting duplicates?

I've built a Keno game, and it picks 20 random numbers out of an arraylist, NumbersToPickFrom. I generate a random number and then check if that number is currently in the numbers available to pick from. If it is, I add it to my arraylist of numbers that will be used as the lottery numbers, randomPicks, and then I remove it from the available numbers. If it's not in the list, that means it's already been picked, and I need a new number. I use a goto to start over. I thought it was working fine, but it seems I've been getting duplicates. Am I using the ArrayList.Remove function wrong? If it's removed, I shouldn't be getting duplicates in my final listing of random picks. If anybody can see where I missed something, that would be helpful. The below code is just the code involved in what I'm talking about.
private void GeneratePicks()
{
for (int i = 1; i <= 20; )
{
Retry:
int rInt = GenerateRandomPick();
if (NumbersToPickFrom.Contains(rInt))
{
RandomPicks.Add(rInt);
NumbersToPickFrom.Remove(rInt);
i++;
//PickBox.Text += rInt + " ,";
RandomPicks.Sort();
}
else
{
goto Retry;
}
}
}
private int GenerateRandomPick()
{
int rInt = rand.Next(1,81);
return rInt;
}
private void initializeArray()
{
for (int i = 1; i <= 80; i++)
{
NumbersToPickFrom.Add(i);
}
}
I ran your code and didn't get any duplicates at all.
Nevertheless, the approach of repeatedly picking random numbers and comparing to the shrinking list isn't the best way to do this.
Try this instead:
RandomPicks =
Enumerable
.Range(1, 80)
.OrderBy(n => rand.Next())
.Take(20)
.OrderBy(n => n)
.ToList();
I found that your code is working fine.
I added the following public variables to make it work though (on my machine)
List<int> NumbersToPickFrom = new List<int>();
List<int> RandomPicks = new List<int>();
Random rand = new Random();
Though on the second run, i found that the number of items in RandomPicks have doubled and there were duplicates as well, so I changed initializeArray() as below
private void initializeArray()
{
for (int i = 1; i <= 80; i++)
{
NumbersToPickFrom.Add(i);
}
RandomPicks.Clear(); // Added this to clear the existing values in the list.
}
If you want to do it "old school" and actually watch what's happening, change your GeneratePicks() method to this:
private void GeneratePicks()
{
RandomPicks = new List<int>();
initializeArray();
for (int i = 0; i < 20; ++i)
{
int randomIndex = rand.Next(1, 80 - i);
int randomPick = NumbersToPickFrom[randomIndex];
RandomPicks.Add(randomPick);
NumbersToPickFrom[randomIndex] = NumbersToPickFrom[80 - i - 1];
}
RandomPicks.Sort();
}
This will run through exactly 20 times and guarantee non-duplicates.
I can't see any error in your code, and tested your code by running it 100000 times and didn't get any duplicates.
There are however better methods for getting random numbers. One easy improvement would be to randomly pick a number from the NumbersToPickFrom list instead of just picking a number, then you don't need the inner loop.
There is a nicer way to pick lottery numbers. You can loop through the numbers and calculate the probability that each number should be picked. The probability of a number being picked is PicksLeft / NumbersLeft, for example the probability for the number 1 to be picked is 20 / 80, and then the probability changes depending on which numbers are picked:
private void GeneratePicks() {
int pick = 20;
for (int n = 1; pick > 0; n++) {
if (rand.Next(81 - n) < pick) {
RandomPicks.Add(n);
pick--;
}
}
}
As the numbers are picked in order, you don't even have to sort the numbers afterwards, and you don't need the NumbersToPickFrom list.

Categories