Reputation: 455
I have working code I got on the internet where a name is randomly picked from Column A with a default counter of "0" (Column B). I added a modification where if the name has been picked, the value of "0" becomes "1". However I am confused as to where I can add the logic where if the value in Column B is already 1, it will not be included in the next random pick since technically, the person with the value of 1 in the counter has already won.
Sample data:
Names | Counter
Newt | 0
Thomas | 0
Teresa | 1
Katniss | 0
Peeta | 0
Gale | 0
Haymitch | 0
Hazel Grace | 0
Augustus | 0
Code when "Draw Winner" is clicked:
Sub draw_winners()
draw
End Sub
Function draw()
Dim x As Integer
Dim delay_ms As Integer
Dim prize_y As Integer
Dim name_matched As Boolean
Dim randm As Integer
x = get_max
'CELL (ROW, COLUMN)
delay_ms = 20 'how many draws before final
draw_winner:
randm = rand_num(x)
Cells(1, 3).Value = Cells(randm, 1).Value
'winner_window.winner_name.Caption = Cells(1, 3).Value
name_matched = check_names(Cells(1, 3).Value, 1)
If delay_ms > 0 Then
WaitFor (0.1)
delay_ms = delay_ms - 1
GoTo draw_winner
End If
If name_matched = True Then
GoTo draw_winner
End If
Cells(randm, 2).Value = 1
End Function
Function check_names(name As String, rndm As Integer) As Boolean
Dim i As Integer
Dim winner As String
check_names = False
i = 2
check_name:
winner = Cells(i, 4).Value
If winner <> "" Then
If winner = name And i <> rndm Then
check_names = True
End If
End If
i = i + 1
If i < 1000 Then
GoTo check_name
End If
End Function
Function get_max() As Integer
Dim i As Integer
i = 2
check_blank_cell:
If Cells(i, 1).Value <> "" Then 'starts at the second row
i = i + 1
If i > 10000 Then
MsgBox "Max Limit Reached!"
Else
GoTo check_blank_cell
End If
End If
get_max = i - 1
End Function
Function rand_num(max As Integer) As Integer
Dim Low As Double
Dim High As Double
Low = 2 '<<< CHANGE AS DESIRED
High = max '20 '<<< CHANGE AS DESIRED
r = Int((High - Low + 1) * Rnd() + Low)
rand_num = r
End Function
Sub WaitFor(NumOfSeconds As Single)
Dim SngSec As Single
SngSec = Timer + NumOfSeconds
Do While Timer < SngSec
DoEvents
Loop
End Sub
Apologies if this has been asked. Your help will be deeply appreciated.
Upvotes: 2
Views: 362
Reputation: 57683
An easy (and fast) way would be to sort data by counter as a first step (so all 0
counters come first) before drawing a new name.
With ActiveSheet.Sort
.SortFields.Clear
.SortFields.Add2 Key:=Range("B:B"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.SetRange Range("A:B")
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
and use the amount of zeros x = Application.WorksheetFunction.CountIf(Range("B:B"), 0)
as maximum for your random number generator rand_num(x)
. This way only names with 0
are drawn.
Image 1: Only the selected rows are used to draw a name.
Also see How to Sort Data in Excel using VBA (A Step-by-Step Guide).
Upvotes: 2
Reputation: 75840
The below will return an array of names that have not yet won. A random name gets picked and column B gets adjusted accordingly. Maybe it comes in handy:
Sub Test()
Dim lr As Long
Dim arr As Variant
Dim nom As String
Dim rng As Range
With Sheet1 'Change accordingly
'Get last used row
lr = .Cells(.Rows.Count, 1).End(xlUp).Row
'Get range into memory (array)
arr = Filter(.Evaluate("TRANSPOSE(If(B2:B" & lr & "=0,A2:A" & lr & ",""|""))"), "|", False)
If UBound(arr) = -1 Then Exit Sub
'Get a random name from array
nom = arr(Int(Rnd() * (UBound(arr) + 1)))
'Get the range where name resides
Set rng = .Range("A2:A" & lr).Find(nom, LookIn:=xlValues, lookat:=xlWhole)
'Change value in B column
rng.Offset(, 1).Value = 1
'Do something with randomly picked name
Debug.Print nom
End With
End Sub
Upvotes: 2