dont want a random number to show twice - c#

I am trying to save random numbers in a list, the same number can not come twice.
It´s a BINGO game where this method is used to display ex B12, then the user hits enter and a new number will show. This will keep on until the user writes q.
This works, BUT the number can show up twice...
static void bingo()
{
Random rnd =new Random();
List<int> check = new List<int>();
string choice = "";
while (choice != "Q")
{
int number = rnd.Next(1, 76);
while (!check.Contains(number))
{
kontroll.Add(number);
}
if (number <=15)
{
choice = Interaction.InputBox("B" + number);
choice = choice.ToUpper();
}
else if(number <= 30)
etc.

Something like this should work (if I'm reading your question correctly)
Enumerable.Range(1,76).OrderBy(n => rnd.NextDouble())

There are a couple of ways to do this:
Keep track of what numbers have been "called" - if a number is in the list, pick a different one
Remove numbers that have been called from the original list, then pick a new one at random each time.
Sort the list of possible values by a random number and just work though the list

The easiest way to accomplish this is to use a HashSet.
var usedNumbers = new HashSet<int>();
...
int number;
do {
number = rnd.Next(1, 76);
} while (usedNumbers.Contains(number));
usedNumbers.Add(number);

Related

C# - Random Generator exclude last number from Array

I've just started my first little project in C# and with WinForms and I am stuck on this one feature for a few days now..
I have an Array with about 60 PictureBoxes in it and when i press a button, I want it to pick one random out of these, but not twice in a row.
I guess I am searching for something like that:
static Random rnd = new Random();
int lastPick;
if (checkBox1.Checked == true)
{
int RandomPick = rnd.Next(pictureBoxArray.Length);
lastPick = RandomPick;
PictureBox picBox = pictureBoxArray[RandomPick **- lastPick**];
picBox.BorderStyle = BorderStyle.FixedSingle;
}
I've also tried to create a List containing my last Pick and tried to use this, but it also didn't work and it gave me an Out of Range Exception.
static Random rnd = new Random();
int lastPick;
List<int> lastNumber = new List<int>();
if (checkBox1.Checked == true)
{
int RandomPick = rnd.Next(pictureBoxArray.Length);
lastPick = RandomPick;
lastNumber.Add(lastPick);
PictureBox picBox = pictureBoxArray[RandomPick - lastNumber.Count];
picBox.BorderStyle = BorderStyle.FixedSingle;
}
Any help or tips to get into the right direction would be appreciated
I feel like you are overcomplicating a problem. You can simply store the latest index in a variable (like you are doing), and then generate a random number until it is something else than the one in the variable. Here's an example code snippet:
int lastPick;
while (true) {
int randomPick = rnd.Next(length);
if (randomPick != lastPick) {
lastPick = randomPick;
// Do things here.
break; // This breaks the loop.
}
// If the previous if-statement was false, we ended
// up with the same number, so this loop will run again
// and try a new number
}
You are close, just pick randomly until the new pick is not the same as the previous one.
int lastPick = -1;
int randomPick = -1;
if (checkBox1.Checked == true)
{
while (randomPick == lastPick)
{
randomPick = rnd.Next(pictureBoxArray.Length);
}
lastPick = randomPick;
PictureBox picBox = pictureBoxArray[randomPick];
picBox.BorderStyle = BorderStyle.FixedSingle;
}
Since the other answers use while loops, I wanted to present a way to do this without a while loop. Create a list of indices initialized to contain all possible indices into your array. This solution requires System.Linq.
Initialize your previous chosen index to -1.
int lastChosenIndex = -1;
Create a list of all possible indices into your array.
List<int> indicesList = Enumerable.Range(0, pictureBoxArray.Length).ToList();
Now when you want an index into your array, you get the index from the indices list.
var randomIndex = random.Next(indicesList.Count - 1);
var randomItem = pictureBoxArray[indicesList[randomIndex]];
We are going to remove this chosen index from the indices list so it cannot be chosen again. First we need to add back the previously removed index (if it is not -1), since it is now a valid selection.
if (lastChosenIndex > -1)
// Use Add so the index into this list doesn't change position
indicesList.Add(lastChosenIndex);
lastChosenIndex = indicesList[randomIndex];
// by removing the index at this position, there is no way to choose it a second time
indicesList.RemoveAt(randomIndex);
The nice thing is, if you wanted to never show a duplicate, you can remove the last chosen index code and it will never show a duplicate. This is a bit long winded compared to the other answers, but wanted to show there is an alternative to using brute force with a while loop.

How can I ensure that same random numbers are not selected every time in C#?

I'm writing a trivia game player app in C#, where the user must pick 5 randomly selected trivia questions from a set of 20 available questions.
I use this code to generate an index that the app will use to fetch the questions:
private void GenerateRandomNumbers(int RandomIndex)
{
Random rand = new Random();
HashSet<int> check = new HashSet<int>();
for (int i = 1; i < RandomIndex; i++)
{
int curValue = rand.Next(1, RandomIndex);
while (check.Contains(curValue))
{
curValue = rand.Next(1, RandomIndex);
}
ChosenQuestions.Add(Questions[curValue]);
check.Add(curValue);
}
check.Clear();
}
The problem is that when the user plays the game a second time (by clicking the "PLAY AGAIN" button) and the above code is executed again, it keeps picking the same random numbers, though they are not necessarily in the same order. this causes the same trivia questions to be chosen every time. I want a fresh new set of totally random numbers every time the above code executes. How can I modify the code to accomplish this?
NOTE: I did copy this code from somewhere else here on Stack Overflow, so it's not my own original code.
Assuming RandomIndex is the number of values to pick. You want this:
rand.Next(1, RandomIndex);
to be
rand.Next(0, Questions.Length);
There is an off by one error in the loop as well. Let's just fix the whole thing:
private void GenerateRandomNumbers(int RandomIndex)
{
Random rand = new Random();
HashSet<int> check = new HashSet<int>();
for (int i = 0; i < RandomIndex; i++)
{
int curValue = rand.Next(0, Questions.Length);
while (check.Contains(curValue))
{
curValue = rand.Next(0, Questions.Length);
}
ChosenQuestions.Add(Questions[curValue]);
check.Add(curValue);
}
}
Also, if you call this in a tight loop, you will get the same values picked repeatedly. This because Random chooses a seed based on the system clock which only upadates every 15 ms or so.
I think that a shuffle would be better approach rather than checking whether indexes have already been picked.
You could seed RNG with different seeds
Random rand = new Random(newSeed);
Seed could be taken from current time, for example
Try using just one global Random object, and not creating a new Random() every time the user plays. This will ensure that isntead of initializing a new seed every time, the numbers will be a sequence created by one seed. This will make them closer to real randomness.

Generate random numbers from 1 to 6 and stop at the last one

I have the following code :
int GetRandNumber()
{
Random r = new Random();
return r.Next() % 6 + 1;
}
I am developing a windows store app. I have a textbox in which a single number from 1 to 6 is generated. For every number I have made a specific event. I need to make sure that every number is generated only once so that the events do not repeat.
Looks like you just need to shuffle numbers. I'd suggest to create an array of numbers from 1 to 6 and just shuffle the array. You can see some code here for how to shuffle an array/list.
First of all you need to be careful with this implementation, if you call GetRandomNumber() multiple times very close together it will give you the same result. A better function would be
int GetRandNumber(Random r)
{
return r.Next(1, 7); //This does the same as "r.Next() % 6 + 1" but removes bias.
}
//used like
Random rand = new Random();
foreach(var foo in bar)
{
//The same instance of rand is used for each call instead of a new one each time.
foo.SomeProp = GetRandNumber(rand);
}
However that is completely separate from what you need to do, you should not be generating random numbers between 1 though 6. What you need to do is make a list of 1 though 6 then shuffle the list, not use random numbers at all (well you will likely use them during the shuffle but that is a implementation detail)
List<int> numbers = new List<int>();
for(int i = 1; i <= 6; i++)
{
numbers.Add(i);
}
MyShuffleListFunction(numbers);
There are plenty of examples on this site on how to make a shuffle function.
Maybe I'm wrong, but as I understand you want something like this as an output:
344213266125
To achieve this you should keep track which numbers are already generated, and stop if all has been "rolled" at least once.
So let's have a bool array initialized to 6 false values, and after each random number generation (after each roll) set the array's corresponing element to true. Check if there are any false values in the array, if not then "roll again".
Also, you might consider generating the numbers according to the other answers, as they are of course right: this is not an ideal way.
Update
Okay, based on your question's update I also update my pseudocode (or maybe I should call this prose):
Keep track of the already "rolled" numbers (as above). When generating a new number check if it has been already generated or not. If it's been rolled before, then roll again, until you roll a new one: then update the array accordingly. Also be sure to check if there is a valid number or all has been rolled before at the beginning of the roll...
But now it seems for me that what you really are looking for is simply a shuffle, which has been proposed in other answers.
Perhaps this will work for you. The approach is to record the random results in a List and to skip the output if the results already exists in the list.
class Program
{
static int tmp;
static void Main(string[] args)
{
List<int> alreadyFired = new List<int>();
while (alreadyFired.Count != 6)
{
Random rng = new Random();
int diceresult = rng.Next(1,7);
foreach (var item in alreadyFired)
{
if (item == diceresult)
{
tmp = item;
}
}
if (!(tmp == diceresult))
{
alreadyFired.Add(diceresult);
Console.WriteLine(diceresult);
}
}
Console.WriteLine("no events left");
Console.ReadKey();
}
}

Generate a random number if the number matched with the previous

I want to create a random number with a text in front of it, and I don't want the system displaying a number twice. So, this is that the way that I did it:
Random _rand = new Random();
private void RandomNumberGenerator()
{
int random = _rand.Next(10000);
string text = "TP0" + random;
if (random.Equals(random))
{
_rand.Next();
}
else
{
random = _rand.Next(10000);
}
MessageBox.Show(text);
}
I am not getting any displayed number twice (but I am not too sure, because I just close the program until it displayed the number 5 times (all of it are not the same number).
Is it possible from the above code to displaying a number twice with any chance?
Thank you.
EDITED to get rid of magic numbers and ensure sanity.
Random _rand = new Random();
HashSet<int> _taken = new HashSet<int>();
object _syncRoot = new object();
private int RandomNumberGenerator() {
lock (_syncRoot) {
const int MAX_NUMBER = 10000;
if (_taken.Count == MAX_NUMBER) {
throw new Exception("All possible numbers are already generated.");
}
int random = _rand.Next(MAX_NUMBER);
while (_taken.Contains(random)) {
random = (random + 1) % MAX_NUMBER;
}
_taken.Add(random);
return random;
}
}
Soner Gonul is correct, random.Equals(random) is always going to be true I think.
You could work around it (roughly) by having another int variable which will become whatever the last number generated was, then when the function goes into it's next cycle have it reference the new random number variable against the one stored in your second variable, which is the previous random number. That's one way of doing it, I can try define that a little clearer in a minute if you don't understand

C# random number generator still gives same number each time [duplicate]

This question already has answers here:
Random number generator only generating one random number
(15 answers)
Closed 9 years ago.
// Create a string array that consists of ten lines.
string[] personalNumbers; // declare personalNumbers as a 10-element array
personalNumbers = new string[10]; //= { "First number", "Second number", "Third line", etc}
for (int i = 0; i < 9; i++) // populate the array with 10 random values
{
Random random = new Random();
int randomNumber = random.Next(1, 50);
string RandomNumberText = Convert.ToString(randomNumber);
personalNumbers[i] = RandomNumberText;
}
Hi, I know that this SEEMS to be a duplicate of previously asked questions, but I am trying to
generate a series of random numbers between 1 and 50 to populate an array
The problem is, if I do it as we were taught in class, each number is the same
I know that the problem is that the tight loop causes the random to be seeded with the same number
What NONE of the other threads addresses however, is HOW to fix this problem when using a loop iteration....
All of the explanations thus far are so far advanced beyond our level that I (and the other askers BTW) have no clue how to implement them as a solution, which I also cannot submit in class as they are techniques that we have not covered
The tutorials at Microsoft insist that putting the random inside the loop is the right solution
I've tried putting an instance of random outside the loop and then calling it from inside the loop but this has caused an exception
Is there a straightforward way to use random to create a series of random numbers that doesn't run into this problem?
Create the random instance outside of the loop:
Random random = new Random();
for (int i = 0; i < 9; i++) // populate the array with 10 random values
{
MSDN:
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. By default, the parameterless constructor of the
Random class uses the system clock to generate its seed value, while
its parameterized constructor can take an Int32 value based on the
number of ticks in the current time. However, because the clock has
finite resolution, using the parameterless constructor to create
different Random objects in close succession creates random number
generators that produce identical sequences of random numbers.
You have to define the Random object outside the loop and just get a number each time inside the loop. If you create it each time again, it will be created with the same initial value because the interval between creations is too small.
Random random = new Random();
for (int i = 0; i < 9; i++) {
int randomNumber = random.Next(1, 50);
}
I've tried putting an instance of random outside the loop and then
calling it from inside the loop but this has caused an exception
Here are two concrete examples, one for a Console app, and the other for a WinForms app.
This is one way to declare it in a Console app. random can be used from anywhere within the application, even in methods other than Main():
class Program
{
private static Random random = new Random();
static void Main(string[] args)
{
// ... code ...
for (int i = 0; i < 9; i++) // populate the array with 10 random values
{
int randomNumber = random.Next(1, 50);
personalNumbers[i] = randomNumber.ToString();
}
// ... code ...
}
}
This is one way to declare it for use in a WinForms app. random in this example can be used anywhere within Form1:
public partial class Form1 : Form
{
private Random random = new Random();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// ... code ...
for (int i = 0; i < 9; i++) // populate the array with 10 random values
{
int randomNumber = random.Next(1, 50);
personalNumbers[i] = randomNumber.ToString();
}
// ... code ...
}
}
This should cover most simple homework assignments. Nothing fancy here.
thank you for the input, it is much appreciated!
I have posted the complete code thus far, which is now giving me what seems like "random" numbers
in that they are always different when I run it
#Steve thank you...I have looked at those questions, but all of the solutions involve using some other technique than random() which I am not allowed to use
#Oerkelens thank you, when I moved the code for random() outside the loop, I got two possible results
one was a series of 9, 9-digit random numbers, or an exception that says
Error 1 A local variable named 'randomNumber' cannot be declared in this scope because
it would give a different meaning to'randomNumber', which is already used in a 'parent or current' scope to denote something else
I have posted the larger bit of code to show what I have changed to get it to work...I don't really understand how to properly call the random() from within the loop, but for some reason, having the same line both inside and outside of the loop did the trick
#Preston - we don't have a textbook for this course, and we are only allowed to use techniques that are contained within the Microsoft C# video tutorials by Bob Tabor (learnvisualstudiodotnet) and Envato (learn C# in 30 days)
I apologize if this all seems obvious to you, but we are in the position of being told that half-way through the course that we are switching from learning to program in Visual Basic to C#, so all of our work now needs to be re-written in C#, without any particular instruction in how to how to use this language...needless to say, it is a huge stress and we are being left without any resources to do this, so much of what we are doing is guesswork
the more complete code that is "working"
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace GuessingGameProgram
{
class Program
{
int randNum;
static void Main(string[] args)
{
// Create a string array that consists of ten lines.
string[] personalNumbers; // declare personalNumbers as a 10-element array
personalNumbers = new string[10]; //= { "First number", "Second number", "Third line", etc}
Random outsideLoopRandom = new Random();
int randomNumber = outsideLoopRandom.Next(1, 50);
for (int i = 0; i < 9; i++) // populate the array with 10 random values
{
randomNumber = outsideLoopRandom.Next(1, 50);
string RandomNumberText = Convert.ToString(randomNumber);
personalNumbers[i] = RandomNumberText;
}
// WriteAllLines creates a file, writes a collection of strings to the file,
// and then closes the file.
//System.IO.File.WriteAllLines(#"C:\Users\Public\TestFolder\WriteLines.txt", lines);
foreach (string i in personalNumbers) // this is just a test to see what the output is
{
Console.Write("{0} ", i);
}
Console.ReadLine();
}
}
}
//randNum = Random.Equals(1, 50);
//StreamReader myReader = new StreamReader("personalNumbers.txt");
//string line = "";
//while (line != null)
//{
// line = myReader.ReadLine();
// if (line != null)
// Console.WriteLine(line);
//}
//myReader.Close();
//Console.ReadLine();
//personalNumbers = RandomNumbers.next(1, 10);
//int returnValue = personalNumbers.Next(1, 50);
//int Guess = 0;
//Console.WriteLine("Please guess a number between 1 and 50");
//Console.ReadLine();
////while (Guess = Convert.ToInt32(Console.Read());
//if (Guess < returnValue)
//{
// Console.WriteLine("Wrong! the number that I am thinking of is higher than " + Guess + ". Try again!");
// Console.ReadLine();
//}
//if (Guess > returnValue)
//{
// Console.WriteLine("Wrong! The number that I am thinking of is lower than " + Guess + ". Try again!");
// Console.ReadLine();
//}
// else if (Guess = returnValue)
// Console.WriteLine("Correct! The number that I was thinking of was " + Guess + ". Congratulations!");
// //{
//Console.WriteLine("Let's play a guessing game!")
//Console.WriteLine("")
//Console.WriteLine("guess a number between 1 and 10")
//Console.WriteLine("")
//randNum = randomGenerator.Next(1, 10)
//While userGuess <> randNum
// {
// userGuess = Console.ReadLine()
// }
// If userGuess > randNum Then
// Console.WriteLine("too high, guess again!")
// {
// If userGuess < randNum Then
// Console.WriteLine("too low, guess again!")
// }
// Else
//End While
//Console.WriteLine("Correct! the secret number is " & randNum)
//Console.ReadLine()

Categories