cycle never reaching final value - c#

This is my random unique numbers generator I try to create for my cards software. It generates numbers and write into array OK. I have problem with the loop here. when integer i reaches 29, it stops growing and code cycles infinitely and never reaches 30, which would stop the loop.
Without the if statement it works, but it won't fill the range needed.
fixed the code, now works OK, the initial value in array was the problem. now I ged needed 0-29 values
public partial class Form1 : Form
{
int[] rndCards = new int[30];
public Form1()
{
InitializeComponent();
richTextBox1.Text = #"random numbers";
}
private void button1_Click(object sender, EventArgs e)
{
int i = 0;
rndCards = new int[30];
richTextBox1.Clear();
Random rnd = new Random();
while (i < 30)
{
int cardTest = rnd.Next(0, 30);
while (rndCards.Contains(cardTest))
{
cardTest++;
if (cardTest == 31)
{
cardTest = 1;
}
}
rndCards[i] = cardTest;
i++;
}
i = 0;
while (i < 30)
{
rndCards[i] = rndCards[i] -1;
richTextBox1.Text += rndCards[i] + ", ";
i++;
}
}
}

You problem lies in the simple fact that the array already contains the number 0 when you create it (because each item of an array is initialized to the default value for its member's type) That's why you should start your i from 1 and not zero.
int i = 1;
Alternative Simpler Approach:
You can do this as a simple random number generation:
Random rnd = new Random();
rndCards = Enumerable.Range(0, 30).OrderBy(x => rnd.Next()).ToArray();
foreach(var card in rndCards)
{
// do something
}

rnd.Next(0,30) would return a random number from 0-29.
From the documentation for Random.Next(Int32, Int32):
The Next(Int32, Int32) overload returns random integers that range from minValue to maxValue – 1. However, if maxValue equals minValue, the method returns minValue.
Use int cardText = rnd.Next(0, 31);, and this should solve your issue.

The upper bound is exclusive (C# Random.Next - never returns the upper bound?).
int cardTest = rnd.Next(0, 31);

Related

C# Checking if there is same random value in the array or not

I want to check if there is same value in the array or not as I mentioned in the title. And if there is, I want to pass that value and check another random value to add to listbox.
In my form, there is 2 textBox, 1 listbox and 1 button. When button is clicked, listbox has to show random numbers up to sum of textbox1 and textbox2. For instance;
5 entered from textbox1 and 10 entered from textbox2. Sum is of course 15 and listbox has to show 15 random numbers but those numbers have to be different from each other.
I wrote something like that and used Contains method to check if there is same value or not. But the program froze and didn't give any error.
int a, b;
Random rnd = new Random();
int[] array;
private void button1_Click(object sender, EventArgs e)
{
a = Convert.ToInt32(textBox1.Text);
b = Convert.ToInt32(textBox2.Text);
int c = a + b;
array = new int[c];
for (int i = 0; i < array.Length; i++)
{
int number = rnd.Next(c);
foreach(int numbers in array)
{
if (array.Contains(numbers))
{
i--;
}
else
{
array[i] = number;
listBox1.Items.Add(array[i]);
}
}
}
I also did it without foreach(Only Contains part I mean). Also didn't work. I wrote in "else";
array[i] += number;
it also didn't work.
I would be very appreciated if you help me. Thanks in advance.
instead of a for loop, use a while loop:
int = 0;
while(i<c)
{
int random rnd.Next(c);
if(!array.Contains(random))
array[i++] = random;
}
you may also create a list of numbers from 1-15 and then shuffle them (as your random function will create only random numbers from 1-15 just random):
array = Enumberable.Range(0,c).OrderBy(x => rnd.Next()).ToArray();
The above code is much faster, because imagine that we have generated 14 random numbers and only one number (5 for instance) left, it has to go through loop several times so that finally random number that is generated equals to 5, but in the above code there is no need to check that, we just have all numbers and then we shuffle it.
You can try to use do...while instead of for loop
Random.Next get the value from 0 to c - 1, so rnd.Next(c + 1); need to add 1 otherwise, the loop will not be stopped.
var array = new int[c];
int number;
for (int i = 0; i < array.Length; i++)
{
do
{
number = rnd.Next(c + 1);
} while (array.Contains(number));
array[i] = number;
listBox1.Items.Add(array[i]);
}
You basically need to shuffle your data. Create a collection with all values:
var temp = Enumerable.Range(0, c);
Now order it by random
temp = temp.OrderBy(_ => rnd.Next());
Now you can add temp to your listBox
Or, as single line:
listBox1.Items.AddRange(Enumerable.Range(0, c).OrderBy(_ => rnd.Next()));

how to fill int array that has unique numbers in every index? [duplicate]

This question already has answers here:
Random number generator in C# - unique values
(5 answers)
Closed 9 years ago.
I'm creating a bingo game and I'm using Random to generate random numbers in an int array but my problem here is that sometimes a number is used again in an index. How can I make the numbers in index unique?
Here is my work:
namespace Bingo
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Random randNum1 = new Random();
int[] random1 = new int[5];
int qwe = 0;
int i = 0;
private void button1_Click(object sender, EventArgs e)
{
Class1 class1 = new Class1();
class1.checker(this);
if (label1.Text == label2.Text || label3.Text == label4.Text) {
label2.Text = randNum1.Next(1, 15).ToString();
label4.Text = randNum1.Next(1, 15).ToString();
}
if (label5.Text == label1.Text || label5.Text == label2.Text) {
label5.Text = randNum1.Next(1, 15).ToString();
}
}
private void Form1_Load(object sender, EventArgs e)
{
Class1 class1 = new Class1();
class1.SetTwo(this);
for (int i = 0; i < random1.Length; i++)
{
random1[i] = randNum1.Next(1, 15);
label1.Text = random1[0].ToString();
label2.Text = random1[1].ToString();
label3.Text = random1[2].ToString();
label4.Text = random1[3].ToString();
label5.Text = random1[4].ToString();
}
}
}
The problem with looping until you found an unused one is that as the game progresses, you'll take longer and longer to find a valid number. It's theoretically possible that your loop will never end (infinitessimally likely, but still...)
The easiest thing to do is what happens in a real Bingo game. Start from a limited set, and actually remove the item from the set each time you draw. Fill a List or any other dynamic indexed container with your initial possibilities, randomly choose an index from 0 to the size of the list, and then remove the selection out of the list.
This will guarantee that every selection produces a unique result, with no looping.
I figured an illustration of Scott Mermelstein's answer may help:
List<int> AvailableNumbers;
Random random;
private void Form1_Load(object sender, EventArgs e)
{
//Create a list of numbers, 1-14
AvailableNumbers = Enumerable.Range(1, 14).ToList();
random = new Random();
label1.Text = GetNextNumber().ToString();
label2.Text = GetNextNumber().ToString();
label3.Text = GetNextNumber().ToString();
label4.Text = GetNextNumber().ToString();
label5.Text = GetNextNumber().ToString();
}
private int GetNextNumber()
{
//Get a random index within the bounds of AvailableNumbers
var nextIndex = random.Next(0, AvailableNumbers.Count);
var nextNumber = AvailableNumbers[nextIndex];
AvailableNumbers.RemoveAt(nextIndex);
return nextNumber;
}
Another approach is to shuffle the sorted list of numbers:
var numbers = Enumerable.Range(1, 15).OrderBy(i => Guid.NewGuid()).ToArray();
How does this work?
start with a list of integers (Enumerable.Range(1, 15) => [1, 2, 3, ..., 15])
reorder them (OrderBy)
with a "random" index Guid.NewGuid()
Obviously, this will only work, if Guid.NewGuid() doesn't produce consecutive GUIDs, but, I think the default doesn't, since that was a security issue with the first implementations of the GUID algorithm.
(I got the shuffling with GUIDs tip from here:
Randomize a List<T>)
You can use other, more efficient methods to shuffle the "deck", but for Bingo style applications, this should work just fine.
Another idea:
var rand = new Random();
var numbers = Enumerable.Range(1, 15).OrderBy(i => rand.Next()).ToArray();
Since the elements in the starting list are unique, the result is guaranteed to reproduce that property.
everytime you grab a new number, just surround it with this :
int num;
do
{
num = randNum1.Next(1, 15);
}
while(random1.Contains(num))
random1[i] = num;
to guarantee it is unique

Wrong output. Where is my random numbers?

I'm new to programming, and I'm reading a book on C#. This code is not outputting what I was expecting.
Here is the code:
public partial class Form1 : Form
{
static string stars = "****************************************************************";
const int MAXVAL = 52;
const int MAXELEMENTS = 100;
int[] data = new int[MAXELEMENTS];
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
int i;
Random rd = new Random(5);
int j;
string buff;
for (i = 0; i < data.Length; i++)
{
data[i] = rd.Next(MAXVAL);
buff = " ";
for (j = 0; j < data[i]; j++)
{
buff += "*";
lstResult.Items.Add(data[i].ToString() + " " + buff);
}
}
}
}
Here is the output:
Why isn't there random numbers in an random order in the listview?
You are seeding the random instance always with the same number 5. That'll cause repeating numbers. You just have to use the default constructor:
Random rd = new Random();
Have a look at the example on MSDN which shows exactly this behaviour.
By the way, this is also a common pitfall, you should always reuse the same random instance instead of creating always a new one(in a loop) since the seed is created from the current time. If you create randoms very fast you'll get the same seed which causes repeating numbers.
Take out the 5 after the Random(), that is a seed value. Just use the default constructor:
Seed - A integer used to set the starting point for generating a series of random numbers. The seed sets the generator to a random starting point. A unique seed returns a unique random number sequence.
Because you are using 5 as a seed every time, you are getting repeating numbers
Random rd = new Random();
The output is logical if you do your Random.Next call outside the j loop and the Items.Add inside it.
I suggest moving the Items.Add call behind the j loop.
You are using the same seed (5) each time with this line Random rd = new Random(5);
Use the default constructor to generate a random number:
Random rd = new Random();
Declare your random class without seed.
Random rd = new Random();

c# dice roll (i <= maxRolls)

I have two issues that I'm not sure how to fix.
diceThrow() is supposed to randomly roll a die and come up with an answer 1-6 multiple times, but only comes up with one 1-6 answer and only does that. i.e. (6, 6, 6, 6, 6, 6, etc)
and for rollDice(), I'm not sure if I just poorly defined "i" or maxRolls, but it should be that when i > maxRolls, the program should end and reset.
Any advice on how to fix either of these is greatly appreciated, thanks!
//somewhere else in code
int maxRolls = RollsNumber();
int throwresult = diceThrow();
int i;
//*******************************
private void rollButton_Click(object sender, EventArgs e)
{
rollDice();
wagerTextBox.Text = null;
wagerTextBox.Text = scoreTextBox.Text;
diceThrow();
MessageBox.Show(Convert.ToString(throwresult));
if (maxRolls < i)
{
MessageBox.Show("You got too greedy.");
//reset the form
}
}
// Decides the maximum number of rolls before the player loses
static public int RollsNumber()
{
Random rolls = new Random();
return rolls.Next(1, 10);
}
// Throws the dice
static public int diceThrow()
{
Random dice = new Random();
return dice.Next(1, 7);
}
private void rollDice()
{
for (i = 0; i <= maxRolls; i++)
{
int wager = Convert.ToInt32(wagerTextBox.Text);
int score = wager * 100;
scoreTextBox.Text = Convert.ToString(score);
}
}
}
}
You are using same seed with the Random.
As msdn states in Random class
The random number generation starts from a seed value. If the same seed is used repeatedly, the same series of numbers is generated. One way to produce different sequences is to make the seed value time-dependent, thereby producing a different series with each new instance of Random.
A simple way in your case is to not create new Random each time.
// Throws the dice
static Random diceRandom = new Random();
static public int diceThrow()
{
return diceRandom .Next(1, 7);
}

Flip a coin problem

I have been playing around and wrote this little piece of code. I am trying to flip a coin defined number of times and then count how many tails and heads I am getting. So here it is:
private void Start_Click(object sender, EventArgs e)
{
int headss = 0;
int tailss = 0;
int random2, g;
string i = textBox1.Text;
int input2, input;
bool NumberCheck = int.TryParse(i, out input2);
if (textBox1.Text == String.Empty) // check for empty string, when true
MessageBox.Show("Enter a valid number between 0 and 100000.");
else // check for empty string, when false
if (!NumberCheck) // number check, when false
{
textBox1.Text = String.Empty;
MessageBox.Show("Enter a valid number between 0 and 100000.");
}
else
{
input = Convert.ToInt32(textBox1.Text);
for (g = 0; g < input; g++)
{
Random random = new Random();
random2 = random.Next(2);
if (random2 == 0)
{
headss++;
}
else if (random2 == 1)
{
tailss++;
}
}
}
heads.Text = Convert.ToString(headss);
tails.Text = Convert.ToString(tailss);
}
The problem is that I keep getting problems while displaying the content. It's not even close to display they right result. Any ideas?
EDIT. Solution: move following line 3 lines up :D
Random random = new Random();
Instead of
for (g = 0; g < input; g++)
{
Random random = new Random();
random2 = random.Next(2);
}
Declare a single Random for use throughout:
private Random randomGenerator = new Random();
private void Start_Click(object sender, EventArgs e)
{
// ...
for (g = 0; g < input; g++)
{
random2 = randomGenerator.Next(2);
}
// ...
}
You should use only one Random object to generate good (as good as default Random does) random sequence.
The default constructor for random take the systmem time as seed. Therefore, if you generate lots of them in a short amount of time they will all generate the same sequence of random numbers. Pull the random object out of the loop and this effect will not occur.
With RandomGenerator. This code will count how many times coin has been flipped. It will end with 3 consecutive HEADS.
private RandomGenerator rgen = new RandomGenerator ();
public void run () {
int value = 0;
int total = 0;
while (value != 3) {
String coinFlip = rgen.nextBoolean() ? "HEADS" : "TAILS";
println (coinFlip);
if (coinFlip == "HEADS") {
value+=1;
} else {
value=0;
}
total +=1;
}
println ("It took "+total+" flips to get 3 consecutive heads");
}

Categories

Resources