Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations TouchToneTommy on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Randomize an array in vb6 1

Status
Not open for further replies.

Davidprince

Programmer
Jul 1, 2003
52
AU
I have an array of 12 numbers say:
Cards(14,10,15,11,9,14,7,10,12,8,11,14)

I would like to randomize the array Cards. Is there a simple solution or is it like the old pick a number from an array (oops hat),for which there are a myriad of solutions?
Thanks for your help
David
 
I would have an array for the order as well. You can have a function shuffle when you need to. It models real card games most effectively. Other implementations would have you maintain a collection of cards in the deck and each time you deal one, pick one randomly from those remaining. It just depends on how you like to model your solutions.

Code:
Sub Shuffle()
  Dim order(1 To 52) As Integer
  Dim colCardsLeft As New Collection
  Dim c As Integer
  Dim rndCard As Integer
  
  ' initialise collection of cards
  ' t0 make use of handly features of collections
  For c = 1 To 52
    colCardsLeft.Add Str(c)
  Next c
  
  ' now shuffle by placing a card in each position
  ' in the deck.  Using the collection's remove method 
  ' to prevent any repeats
  c = 1
  Randomize Timer
  While colCardsLeft.Count > 0
    rndCard = Int(Rnd() * colCardsLeft.Count) + 1
    order(c) = CInt(colCardsLeft(rndCard))
    colCardsLeft.Remove (rndCard)
    c = c + 1
  Wend

  ' take a look at the shuffle
  For c = 1 To 52
    Debug.Print order(c); " ";
  Next c
  
  Debug.Print
End Sub
 
I also whipped this generic array shuffler up and you can guess that the answer to whether ther eis a simple (i.e. one command) method to randomize and array is nope.

This shuffler works on the idea of swapping the position of two items in the array. When calling the function, you choose how many times to swap two items (much like in cards, how long you shuffle for).

Code:
Sub ShuffleArray(ByRef anArray As Variant, shuffle_time As Long)
  Dim tmp As Variant
  Dim rndPos1 As Long
  Dim rndPos2 As Long
  Dim lower_bound As Long
  Dim upper_bound As Long
  
  upper_bound = UBound(anArray)
  lower_bound = LBound(anArray)
  Randomize Timer
  
  While shuffle_time > 0
    rndPos1 = Int(Rnd() * (upper_bound - lower_bound + 1)) + lower_bound
    rndPos2 = Int(Rnd() * (upper_bound - lower_bound + 1)) + lower_bound
    tmp = anArray(rndPos1)
    anArray(rndPos1) = anArray(rndPos2)
    anArray(rndPos2) = tmp
    shuffle_time = shuffle_time - 1
  Wend
End Sub
Sub test9()
  Dim anArray As Variant
  Dim c As Long
  anArray = Array(14, 10, 15, 11, 9, 14, 7, 10, 12, 8, 11, 14)
  ShuffleArray anArray, 50
  For c = LBound(anArray) To UBound(anArray)
    Debug.Print anArray(c); " ";
  Next c
  Debug.Print
End Sub
 
I like your first one better than your second one. I don't see where your second one excludes repeat shuffles.

If I were going to do the second one, rather than swapping values, I would create a target array, iterate through the source array, generate a random number between lbound and ubound, and assign the current source array element in the loop to the element matching the random number in the target array. To make it more efficent in terms of unsuccessful random number searches, you could simply assign the last ones in order if they represented less than, say, 10 percent of the whole.

HTH

Bob
 
I prefer the second one because it is truer to real shuffling. When shuffling you are (generally) repeating an operation of swapping card positions multiple times.

People too small to shuffle will often put all the cards on a surface and mix them up in big circular motions of the arms so that's why I say "generally".

The second algorithm mitigates the issue of repeatedly selecting the same two cards over and over by repeating the shuffle action many times. Given enough repetitions, this should prove more reliable than the single pick method of algorithm 1. I tested the second method with iterations of 500, 5000, 50000 and I found no difference in my perception of how long it took to output the results. Modern processing power certainly has come a long way since my 8-bit Atari days ;)

But both are "random enough" given the right parameters for most needs which I am sure you will agree.
 
Yes, I liked your swap for the same reason, but didn't realize the number of iterations you could practically perform, which does mitigate the repetition problem. So, I take your point. :)

is a good article on using Windows' cards.dll to expose a set of cards. Though the code in the example is in vb.Net, it's pretty simple and you shouldn't have trouble translating it to vb6.

Bob
 
You probably won't be surprised to find that I provided an example of using cards.dll for VB6 some time back in this forum ... and then the thread vanished, so I repeated it in the API forum: thread711-635472

As a side note, I also tend to use a shuffle for this sort of thing - but only bother running through the 'deck' once as follows:
Code:
[blue]
    Randomize
    For lp = LBound(srcArray) To UBound(srcArray)
        temp = srcArray(lp)
        target = Rnd() * UBound(srcArray)
        srcArray(lp) = srcArray(target)
        srcArray(target) = temp
    Next
[/blue]

since, if VB's random number generator is working properly, additional swapping beyond this will not make the deck any more random
 
strongm, Ahh but haven't you ever been playing cards and someone is shuffling for so long that you wonder how many times during their shuffle, they completely reordered the pack into ranks and suits? hehe

You deny the PC processor the pleasure of that particular thought process by going through only once.

-----P.S.
I reliase your code was just off the cuff but you're probably a perfectionist even in off the cuff code so you'd appreciate my pointing out the mistake in line 4 or 6 :D

Cheers
 
>completely reordered the pack into ranks and suits?

As an amateur card magician, I can tell you that this is easier than you might think ...

>the mistake in line 4

Sure, We should have

target = Rnd() * (UBound(srcArray) + 1)

(although it doesn't matter too much, because that element still gets swapped due to the iteration)
 
I would have thought:

target = Rnd() * (UBound(srcArray)) + LBound(srcArray)

Cheers
 
Nah, only if you think I'm giving production code as opposed to a thrown together example using an abitary zero-based array ... (obviously I confused matters by using LBound in the loop, though) ... if that wasn't the case, I'd go with your recommendation :)
 
Maybe I am being redundant, but what about something simple like this:

Dim Rand_Num As Integer
Dim cards As Variant
Dim Card as Integer

cards = array(14,10,15,11,9,14,7,10,12,8,11,14)

Randomize

Rand_Num = CInt(Rnd * 11)
card = cards(Rand_Num)

LF







"As far as the laws of mathematics refer to reality, they are not certain; as far as they are certain, they do not refer to reality."--Albert Einstein
 
Because with that solution you can pick the same number ('card') multiple times, which is what all our previous solutions have been avoiding. Although if you do use this technique there is quite a neat way of avoiding this problem:
Code:
[blue]Dim Rand_Num As Integer
Dim cards As Variant
Dim Card As Integer

cards = Array(14, 10, 15, 11, 9, 14, 7, 10, 12, 8, 11, 14)

Randomize
Do Until UBound(cards) = 0
    Rand_Num = CInt(Rnd * UBound(cards))
    Card = cards(Rand_Num)
    cards(Rand_Num) = cards(UBound(cards))
    ReDim Preserve cards(UBound(cards) - 1)
    Debug.Print Card
Loop[/blue]

 
Unfortunately this shuffling program has taken on a life of it's own and I'm now looking for an algorithm to do what the casinos call a shimmy. Mr Lewis wrote in his second reply to my query:
"People too small to shuffle will often put all the cards on a surface and mix them up in big circular motions of the arms so that's why I say "generally"."

This sums up what a shimmy is perfectly. The only change is that it is done only when there are new cards which are in a set order. Has anyone come across an algorithm for this situation?
Regards
David
 
Hmmm programming a shimmy (never knew it had a name) is intriguing. So many things to consider. I think too many things to consider to ever model it accurately - unless there is a machine that does the shimmy already.

As i picture the actions involved in my mind, I can see that it's a 3-d spatial model since cards can overlap. The degree, speed and force of the shimmy motion would be variables, as would card thickness, surface friction of table and card, length of time of shuffle etc.

The thing is though, that no matter what happens while someone is shimmying those cards, they still drag them back into a stack. So you can simplify your issue somewhat by thinking about that motion of bringing them back in to a uniform stack.

Funnily enough, this puts you back at the start of your question and really, the solutions posted all seem valid to me. If a shimmy is known to be biased in one direction or another, then you could work that in to the shuffle too. But I think you'd be in a lot of troiuble if you ever said that you thought it was not random :) Those Las Vegas types might not like that at all heh

 
Mr Lewis
Points raised duly noted and I agree that conceptually it is something of a conumdrum, however there is a simple solution that being that you do the shimmy outside the program and then input the result for the program to shuffle.

Thanks for your input,
David
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top