-2

I'm creating a simple game in VB, as the player takes a shot, the is a random chance it will miss, as multiple shots are taken in each point, i new a new random number when the "Sub playShot()" repeats, the number needs to be between 1 and 10.

This is what i currently have, but it just outputs the same number:

Dim rnd As New Random
Dim shot As Integer = rnd.Next(1, 11)

I'm fine if it repeats the number due to chance, but currently it is always the same.

  • 1
    it can be because you each time initialize new Random object and then getting .Next(1,11) from it. Declare your "rnd" as private field in class and intialize it only once. When you will execute .Next() on same object it should return mostly different results. – Epsil0neR Sep 14 '18 at 13:24
  • 2
    If it is not allowed to repeat then it isn't a random number. Do *not* create a Random object over and over again. And google "vb.net random shuffle". – Hans Passant Sep 14 '18 at 13:28
  • You certainly shouldn't be creating a new `Random` object every time you need a new number because the whole point is that an instance generates a pseudo-random sequence of numbers. Create one instance and use that every time. That said, what you're doing will only be an issue if you're creating multiple instances very quickly. Without a seed specified, it will use the current system time as a seed. Two instances created very quickly can use the same seed and thus produce the same sequence of numbers. – jmcilhinney Sep 14 '18 at 13:30
  • As suggested, if you actually want a random number then repeats should be allowed. There can be situations where you want to make random selections from a list and remove an item though, e.g. selecting lottery numbers. In that case, put all the items in a list, randomise that list and then start taking numbers in sequence from the beginning of the list. – jmcilhinney Sep 14 '18 at 13:32
  • Possible duplicate of [How do I ensure unique random numbers are used in a simulation?](https://stackoverflow.com/questions/50878112/how-do-i-ensure-unique-random-numbers-are-used-in-a-simulation) – TnTinMn Sep 14 '18 at 15:19
  • Possible duplicate of [Collections.shuffle() equivalent in vb.net?](https://stackoverflow.com/questions/20443946/collections-shuffle-equivalent-in-vb-net) – the_lotus Sep 14 '18 at 15:36

2 Answers2

1

It just so happens that I have a project open right now that contains extension methods for randomising a list of objects:

Imports System.Runtime.CompilerServices

''' <summary>
''' Contains methods that extend the <see cref="IEnumerable(Of T)"/> interface.
''' </summary>
Public Module EnumerableExtensions

    ''' <summary>
    ''' A random number generator.
    ''' </summary>
    Private rng As Random

    ''' <summary>
    ''' Randomises the items in an enumerable list.
    ''' </summary>
    ''' <typeparam name="T">
    ''' The type of the items in the list.
    ''' </typeparam>
    ''' <param name="source">
    ''' The input list.
    ''' </param>
    ''' <returns>
    ''' The items from the input list in random order.
    ''' </returns>
    <Extension>
    Public Function Randomize(Of T)(source As IEnumerable(Of T)) As IEnumerable(Of T)
        EnsureRandomInitialized()

        Return source.Randomize(rng)
    End Function

    ''' <summary>
    ''' Randomises the items in an enumerable list.
    ''' </summary>
    ''' <typeparam name="T">
    ''' The type of the items in the list.
    ''' </typeparam>
    ''' <param name="source">
    ''' The input list.
    ''' </param>
    ''' <param name="random">
    ''' A random number generator.
    ''' </param>
    ''' <returns>
    ''' The items from the input list in random order.
    ''' </returns>
    <Extension>
    Public Function Randomize(Of T)(source As IEnumerable(Of T), random As Random) As IEnumerable(Of T)
        Return source.OrderBy(Function(o) random.NextDouble())
    End Function

    ''' <summary>
    ''' Initialises the random number generator if it is not already.
    ''' </summary>
    Private Sub EnsureRandomInitialized()
        rng = If(rng, New Random)
    End Sub

End Module

With that module in your project, you can do things like this:

Dim numbers = Enumerable.Range(1, 10).Randomize()

For Each number In numbers
    Console.WriteLine(number)
Next

That module contains two overloads, with the second allowing you to pass in your own Random instance if desired. If you only ever want to use the first overload then the module can be simplified somewhat:

Imports System.Runtime.CompilerServices

''' <summary>
''' Contains methods that extend the <see cref="IEnumerable(Of T)"/> interface.
''' </summary>
Public Module EnumerableExtensions

    ''' <summary>
    ''' A random number generator.
    ''' </summary>
    Private rng As Random

    ''' <summary>
    ''' Randomises the items in an enumerable list.
    ''' </summary>
    ''' <typeparam name="T">
    ''' The type of the items in the list.
    ''' </typeparam>
    ''' <param name="source">
    ''' The input list.
    ''' </param>
    ''' <returns>
    ''' The items from the input list in random order.
    ''' </returns>
    <Extension>
    Public Function Randomize(Of T)(source As IEnumerable(Of T)) As IEnumerable(Of T)
        rng = If(rng, New Random)

        Return source.OrderBy(Function(o) rng.NextDouble())
    End Function

End Module
jmcilhinney
  • 50,448
  • 5
  • 26
  • 46
0

When you have a range where you don't want the random values to repeat, the normal solution is to generate all the numbers in the range (in this case 1 through 10) in sequence. Then you shuffle the sequence. Now you can iterate through your shuffled data.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794