VBScript generating same random number when in loop - how to solve? - random

So I have this function which generates a random string of digits 8 characters long. It works if its called once per page, ie if I refresh it will show a new number.
But I want to generate many of these inside a loop and its returning the same number. How can I solve this?
Function generateCode()
pChar = "0123456789"
pCount = Len(pChar)
Dim psw
psw = ""
Randomize
For i = 1 To 8 ' password length
psw = psw & Mid( pChar, 1 + Int(Rnd * pCount), 1 )
Next
generateCode= psw
End Function
Now I thought Randomize may be based off the current time, so I took the Randomize line out and called Randomize before the loop that calls generateCode() i- still didn't work!

Randomize without any arguments seeds the pseudo-random number generator using the system time. If you call it multiple times very quickly the system time won't have changed so you will reinitialize the PRNG with the same seed each time, giving the same random numbers.
You should only call Randomize only once on your page, not multiple times.

Related

Why does my "random key code" creates a same key every once in a while?

I`m having the following code from which I extract randomPW for my db.
I need this string of random characters in order to use it a primary key in my Db. The problem is that I`m getting quite a lot of duplicates when I execute this code more than once or if I get a Loop in order to extract (for example) 100 keys at once.
If I try to reload the page in order to insert one by one key the same problem occurs... every 50-80 reloads there is a duplicate. What's wrong with my code?
<%
Function RandomPW(myLength)
Const minLength = 6
Const maxLength = 20
Dim X, Y, strPW
If myLength = 0 Then
Randomize
myLength = Int((maxLength * Rnd) + minLength)
End If
For X = 1 To myLength
Y = Int((3 * Rnd) + 1) '(1) Numeric, (2) Uppercase, (3) Lowercase
Select Case Y
Case 1
'Numeric character
Randomize
strPW = strPW & CHR(Int((9 * Rnd) + 48))
Case 2
'Uppercase character
Randomize
strPW = strPW & CHR(Int((25 * Rnd) + 65))
Case 3
'Lowercase character
Randomize
strPW = strPW & CHR(Int((25 * Rnd) + 97))
End Select
Next
RandomPW = strPW
End Function
%>
I expect my code to extract a string that will not duplicate every now and then.
I need this string of random characters in order to use it a primary key in my Db.
In this case I would recommend to use Scriptlet.TypeLib :
Function RandomPW(myLength)
Set TypeLib = CreateObject("Scriptlet.TypeLib")
If myLength < Len(TypeLib.Guid)
RandomPW = Left(TypeLib.Guid, myLength)
Else
RandomPW = TypeLib.Guid
End If
End Function
Randomize is not supposed to be used more than once, unless you want to make sure you are creating fake, repeatable randomness. Per docs, helpfully linked by Lankymart (emphasis mine):
Randomize uses number to initialize the Rnd function's random-number generator, giving it a new seed value. If you omit number, the value returned by the system timer is used as the new seed value.
The system timer referred to above is in seconds; which means, successive calls to Randomize in short succession will make sure the following Rnd is yielding the same value.
It would likely help you immensely to remove all calls to Randomize.

Looping error, too many records added

Ive been trying to write Access VBA code to automate the addition of replicates for germination tests.
Basically I have a form where I enter the total number of Reps (NoofReps) and the number of seeds per rep (RepSize) (e.g. 50 seeds). For each record added I want it to automatically add a record for each rep and automatically calc the Rep Number (i.e if i have 4 reps then it should add 4 records, numbered 1-4 reps) as well as the RepSize (e.g 50).
I have been trying out various loops based on information from this forum and other but am still getting errors with the number of records that it generates. I have tried both the "Do while" and "Do Until" but get the same result below either way.
Could someone please let me know where I am going wrong?...If i want 2 reps then it adds 2, If i want 3 then its 246, and if i want 4 it adds >30,000!!!
For the purposes of trying to fix the code I have started to type the number of reps manually into the code in the iNoofReps so that I know the error is in the code and not from the form.
Private Sub CmdAddReps3_Click()
Dim iRepNo As Integer ' stores the current value in the series
'Open the table
Set db = CurrentDb()
Set rstGReps = db.OpenRecordset("tblGReplicates")
' Initialise the variables
iRepNo = 1
iNoofReps = 3 'iNoofReps = Me.txtNoofReps
' Add the records using a loop
rstGReps.movefirst
Do 'Until rstGReps("RepNo") = (iNoofReps + 1) ' always want to include at least 1 repNo
rstGReps.AddNew
rstGReps("GTestID") = Me.GTestID
rstGReps("RepNo") = iRepNo
rstGReps("NoofSeed") = Me.txtNoOfSeeds
' Calculate the next RepNo value in the loop
iRepNo = iRepNo + 1
rstGReps.Update
rstGReps.moveNext
Loop Until rstGReps("RepNo") = (iNoofReps) + 1 ' so that the loop includes the final repNo.
MsgBox "Finished Looping"
rstGReps.Close
Set rstGReps = Nothing
Set db = Nothing
End Sub
Any help would be appreciated!!!
Well, you're moving next here: rstGReps.moveNext, and then you're comparing rstGReps("RepNo") = (iNoofReps) + 1 after moving next, thus being on an empty record, thus always equating to false.
Loop Until iRepNo = (iNoofReps) + 1 should fix it, then you're no longer referring to the recordset, which has already been set to the next record by the time you're referring to it.
You could also fix it by just eliminating this line:
rstGReps.moveNext
Since rstGReps.AddNew already moves the recordset to a new blank record, moving it forward after adding the record doesn't make much sense. If you remove it, you might want to remove the + 1 in Loop Until rstGReps("RepNo") = (iNoofReps) + 1

Generating Random Numbers and Letters

Keep getting this error sometimes when mid is ZERO:
Invalid procedure call or argument: 'Mid'
How would I fix this?
Function CreateRandomString(iSize)
Const VALID_TEXT = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
Dim sNewSearchTag
Dim I
For I = 0 To iSize
Randomize
sNewSearchTag = sNewSearchTag & Mid(VALID_TEXT,Round(Rnd * Len(VALID_TEXT)),1)
Next
CreateRandomString = sNewSearchTag
End Function
For the random range to be correct you need to make sure the random value generated is between 1 and the length of the VALID_TEXT string value.
The simple formula to do this using Rnd() is
(Rnd() * Len(VALID_TEXT)) + 1
also move Randomize() outside the loop, as it is you'll just make it less random as you're resetting the seed with every iteration of the loop.
The reason for the error is Mid() expects a valid start and size, which a zero value is not. See this question for more information.
More information about random number ranges can be found in this answer to another question.
The second argument of Mid is 1 based. That means that if you did:
Mid(VALID_TEXT,1,1)
you will get "a", not "b" as you might be expecting.
An easy fix would be to add 1 to the second argument, but then you'll run into the same problem on the top end. Typically people will round a random number down after multiplying it instead of using Math.Round, either view Math.Floor or Integer truncation.

Trying to make my own vbscript

I have been working on this vb script for around an hour trying to get it to work there is many skype spammer scipts but i want to make one that includes a random number generator my script is this i call it at the moment "Skype_randizer_mk1"
If anyone would be able to take a look at it it would be greatly appreciated.
When i was posting this the website said i had to indent this so it may look a little strange
The Delay variable is the amount of time it will take to enter another number
I don't mind if this program makes only numerical values that is what i intend for it to do
set shell = createobject ("wscript.shell")
dim max
dim min
dim delay
max = 100
min = 1
delay = 0.00000001
for i = 1 to 5
randomize
intnumber = int((max - min + 1) * rnd + min )
wscript.echo intnumber
Next
for b=1 to delay
shell.sendkeys (intnumber)
wscript.sleep(delay)
if not isnumeric(delay) then
wscript.quit
end if
msgbox "You have 5 seconds to get to your inputbox."
wscript.sleep ( 5000 )
Next
You have lots of problems with your code:-
You should ALWAYS declare your variables using Dim: e.g. Dim shell
You are missing a Next for one of your For loops
Line 10 doesn't make much sense. It says: for b=1 to delay, but delay = 0.00000001, so your loop will never run. Also, why does this section even need to loop? I think you probably just want an If/Then/Else
Line 11 should probably say shell.SendKeys, not strshell.sendkeys as this is an uninitialised variable
Line 13 is checking for a numeric delay value. How will this ever be anything other than numeric when you are assigning a value of 0.00000001 on line 4 and it never changes. As a result, you will not exit the script until the for loop on line 5 has executed 5 times.

Non repeating positive random numbers, over a given range

am generating a game using vb 6.0, at one face i need to generate non repeating random numbers between 1 and 100. am using the following code for generating the random numbers
dim n(10) as integer
for i=0 to 9
n(i)=round(rnd*100)
next i
the code is within a for loop hence it generate 10 Nos. randomly, but it includes repeating numbers and also '0', is their any suggestion to avoid repeating numbers and '0'
then output of my code is:
n()={42,14,10,22,5,42,12,0,59,72}
the numbers 42 is appear two times in the array and 0 cannot be avoided
thanks in advance
Here is a simple technique
Dim n(10) As Integer
Dim choice(100) As Integer
' Create a list of possible numbers
For i = 0 To 100
choice(i) = i
Next
' Populate the array with unique numbers
For i = 1 To 10
lastix = 101 - i
' Find one that has not been selected
ix = Round(Rnd * lastix)
' Assign it
n(i) = choice(ix)
' Replace with one that has not been used
choice(ix) = choice(lastix)
Next
You can use the same technique for shuffling cards.
To avoid 0, multiply by 99 and add 1. To avoid duplicates, keep track of what you generated and retry if you get a duplicate. (Since you need only a few numbers. If you need many, shuffle an array of all possible outcomes and take the initial members.)
the solution below is not the fastest, but makes up by that for being easy ...
it uses a hidden listbox control which contains the required values and retreives a random one every time
the values in this example are just the squared numbers of the index
run the project and click the command button to see what happens. it should show messageboxes with the square numbers in random order
'1 form with:
'1 listbox control : name=List1
'1 command button : name=Command1
Option Explicit
Private Sub Command1_Click()
Dim intIndex As Integer
'generate a new random sequence every time
Randomize Timer
'loop through the list and retreive 1 random value at a time
With List1
Do While .ListCount > 0
intIndex = Int(Rnd * .ListCount)
MsgBox .List(intIndex)
'remove the used item from the list
.RemoveItem intIndex
Loop
End With 'List1
End Sub
Private Sub Form_Load()
Dim intIndex As Integer
'hide listbox
List1.Visible = False
'fill listbox with values (squares)
List1.Clear
For intIndex = 1 To 10
List1.AddItem CStr(intIndex * intIndex)
Next intIndex
End Sub
btw i am just using 10 numbers so you dont have to click through 100 messageboxes :)

Resources