1

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();
        }
    }
}
BartoszKP
  • 34,786
  • 15
  • 102
  • 130
Marilou Magat
  • 37
  • 1
  • 2
  • 12
  • 1
    Check if your Random Number exist in the array and only add it if it doesn't . – Habib Oct 09 '13 at 14:03
  • if you want to use it for a "real game" then the selection should cryptographically strong to ensure a "fair" randomness. http://stackoverflow.com/a/19275698/659190 – Jodrell Oct 09 '13 at 15:23

4 Answers4

7

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.

Scott Mermelstein
  • 15,174
  • 4
  • 48
  • 76
  • this is definitely a better approach – Jonesopolis Oct 09 '13 at 14:12
  • +1 Great approach, I am not sure if it is Kosher to do so, but I created an answer based on yours. Is it what you had in mind? – Khan Oct 09 '13 at 14:29
  • 1
    best to use a collection class with good remove performance and, if the game is real, i.e. for money, use a good quality, evenly distributed random number generator. http://stackoverflow.com/a/19275698/659190 – Jodrell Oct 09 '13 at 15:25
2

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;
}
Khan
  • 17,904
  • 5
  • 47
  • 59
  • 1
    That looks great, and adds value (namely, some actual code) that was sorely lacking in my answer. – Scott Mermelstein Oct 09 '13 at 14:46
  • The one mistake you made is putting `new Random()` inside the function, make it outside of the function and declare it new in the `Load` statement. – Scott Chamberlain Oct 09 '13 at 15:11
  • @ScottChamberlain Good point. I made an edit to my answer accordingly. I did not understand why until I read this: "Each time you create an instance, it will use the current time as the 'seed'" From: http://stackoverflow.com/questions/1011198/non-repetitive-random-number-c-sharp – Khan Oct 09 '13 at 15:20
  • @Khan better still, don't use `Random`, use `RNGCrptoServiceProvider`, `Random` is quick but has an uneven, predictable output. – Jodrell Oct 09 '13 at 15:31
1

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.

Community
  • 1
  • 1
Daren Thomas
  • 67,947
  • 40
  • 154
  • 200
0

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

Jonesopolis
  • 25,034
  • 12
  • 68
  • 112