0

I'm trying to randomly generate a list of numbers from 1 - 24 separated by a pipe key. I've manage to get it working except that it generates the same exact number order every time "17|13|14|7|8|19|1|20|18|2|10|21|9|24|23|15|12|16|22|6|3|4|5|11". How do I get it to be truly random?

   Public Function DoesNoAlreadyExistInList(TheNumber As Integer, TheList As String) As Boolean
        Dim counter As Integer = 0
        If (TheList = Nothing Or TheList = "") And Not (TheList.Contains("|")) Then
        Else
            Dim numberlist() As String = TheList.Split("|")
            For Each n As String In numberlist
                Dim n_ As Integer = n
                If n_ = TheNumber Then
                    counter += 1
                Else
                    counter += 0
                End If
            Next
        End If
        If counter = 0 Then
            DoesNoAlreadyExistInList = False
        Else
            DoesNoAlreadyExistInList = True
        End If
End Function


   Protected Sub new_game_Click(sender As Object, e As EventArgs) Handles new_game.Click
        Dim intNo As Integer
        Dim blnExists As Boolean
        Dim counter As Integer = 0
        'Clear the listbox
        player1_cards.Value = Nothing
        'Do 25 times
        For intI = 0 To 23
            'Do this until we no the number is not already in the list
            Do
                'Get a random no 1 - 50
                intNo = Int((24 * Rnd()) + 1)
                'Check if the number is already in the list.
                blnExists = DoesNoAlreadyExistInList(intNo, player1_cards.Value)
            Loop Until blnExists = False
            'Add the number into the listbox.
            counter += 1
            If counter = 1 Then
                player1_cards.Value = player1_cards.Value & intNo
            Else
                player1_cards.Value = player1_cards.Value & "|" & intNo
            End If
        Next
        right_player_number.Text = player1_cards.Value
    End Sub

3 Answers3

0

See answer from Peter O.

I placed "Randomize()" before "intNo = Int((24 * Rnd()) + 1)" in my code above that fixed my problem.

  • Then you did it wrong. You call `Randomize` once and once only, not before every random number generated. Do it in the `Startup` event handler of your application or in the `Load` event handler of your startup form. Even better, pretend that you're not using VB6 and use the .NET `Random` class. – jmcilhinney Apr 09 '20 at 04:47
0

A list in .net refers to List(Of T) where T is the Type. I created a List(Of Integer) to hold the unique random numbers. Since you refer to adding number to listbox I assumed player1_cards is an

<asp:ListBox ID="NumbersListBox" runat="server" />

I just changed the ID to suit me. Not important.

I cleared the DataSource and the ItemsCollection or the list box.

I created an instance of the Random class (included in the .net framework) outside of the method. I can be used in any method in the Class. I used the .Next method to get a random number. I checked with the .Contains method of the list and added it to the list if it wasn't already there. After that, it exits the Do and continues with the For loop. If it does exist the Do loops again until a unique entry is returned.

Finally, set the DataSource of the list box and DataBind to display the numbers.

If all you need is the String I showed how to do that with String.Join.

Dim rand As New Random

Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim intNo As Integer
    Dim lst As New List(Of Integer)
    'Clear the listbox
    NumbersListBox.DataSource = Nothing
    NumbersListBox.Items.Clear()
    'Do 25 times ?????
    'This does not loop 25 times; it loops 24 times
    For intI = 0 To 23
        Do
            'Get a random no 1 - 50
            'rand.Next(inclusive of first value, exclusive of second value)
            intNo = rand.Next(1, 51)
            'Check if the number is already in the list.
            If Not lst.Contains(intNo) Then
                lst.Add(intNo)
                Exit Do
            End If
        Loop
    Next
    'Add the numbers into the listbox.
    NumbersListBox.DataSource = lst
    NumbersListBox.DataBind()
    NumbersListBox.SelectedIndex = 0
    right_player_number.Text = NumbersListBox.SelectedItem.ToString
    'To put the numbers into a String separated by a |
    Dim s = String.Join("|", lst)
    Debug.Print(s)
End Sub

Your Function wasn't needed with this code.

Mary
  • 14,926
  • 3
  • 18
  • 27
0

If what you actually want is the numbers from 1 to 24 in random order then I would suggest the following:

Dim rng As New Random
Dim numbers = Enumerable.Range(1, 24).OrderBy(Function(n) rng.NextDouble())

You can add a ToArray call to the end of that second line if you want the randomised numbers in an array. What that does is basically generate a random value to represent each number and then sort the numbers by those random values. It is much like the overload of Array.Sort that sorts two concurrent arrays using one of them as keys to sort the other. If you wanted to do it manually, it would look like this:

Dim rng As New Random
Dim numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}
Dim keys = {rng.NextDouble(),
            rng.NextDouble(),
            rng.NextDouble(),
            rng.NextDouble(),
            rng.NextDouble(),
            rng.NextDouble(),
            rng.NextDouble(),
            rng.NextDouble(),
            rng.NextDouble(),
            rng.NextDouble(),
            rng.NextDouble(),
            rng.NextDouble(),
            rng.NextDouble(),
            rng.NextDouble(),
            rng.NextDouble(),
            rng.NextDouble(),
            rng.NextDouble(),
            rng.NextDouble(),
            rng.NextDouble(),
            rng.NextDouble(),
            rng.NextDouble(),
            rng.NextDouble(),
            rng.NextDouble(),
            rng.NextDouble()}

Array.Sort(keys, numbers)

If you want those numbers is a single String, separarted by pipes, do this:

Dim text = String.Join("|", numbers)

You don't need the ToArray call to do that as String.Join will accept an IEnumerable(Of T).

In case you're wondering, I used NextDouble instead of Next because it is more efficient. When generating a random Integer in a range, the first step is to generate a random Double, which is then scaled and rounded. Because these values are being used just for sorting, it's their randomness that matters and not their actual values. As such, the extra steps of scaling and rounding each random Double are pointless.

jmcilhinney
  • 50,448
  • 5
  • 26
  • 46