Random Number Guessing Game for Visual Basic 6.0 - vb6

I'm trying to make a program that will generate a random number, and you have to guess it by typing in the answer. The problem is that it won't match the right number as shown.
Objects:
2 Labels, 1 textbox, 1 Command button
My first code:
Private Sub Command1_Click()
Dim Num, Random As Integer
Label2.Caption = ""
Num = Val(Text1.Text)
Randomize (Random)
Random = Val(Label1.Caption)
Label1.Caption = Int(10 * Rnd + 1)
For Num = 1 To Num
If Num = Random Then
Label2.Caption = "you won "
Else
End If
Next
End Sub

you don't need that for loop, its checking each number up to the number you guessed.
Private Sub Command1_Click()
Dim Num, Random As Integer
Label2.Caption = ""
Num = Val(Text1.Text)
Randomize (Random)
Random = Val(Label1.Caption)
Label1.Caption = Int(10 * Rnd + 1)
If Num = Random Then
Label2.Caption = "you won "
Else
End If
End Sub
to debug it put
If Num = Random Then
Label2.Caption = "you won "
Else
Label2.Caption = "The number " & Num & " Does not equal " & Random
End If

First of all, the current code will always result in number zero being the first "randomly" generated number. Second, the formula will produce a predictable random number sequence.
The issue behind this is that computers are not smart and cannot really create random numbers, that's why you need to "seed" them with Randomize to sort of "shake" the dice and come up with a different number. But, if you randomize with the same number, it will produce exactly the same sequence of "random" numbers.
For example, if you use your code, it will always produce the following sequence of numbers: 0, 8, 7, 5 ...
That's why you need to "seed" the random number with... a random number! LOL. But how do you get a random number? Technically, you can't, but you can cheat. You can do Randomize (Timer) or Randomize, which takes Timer as a parameter and what it does is "seeds" the random number generation with a number of seconds and milliseconds elapsed since midnight. So, the only time where you will get the same sequence of random numbers if you click the button to guess the random number every day at exactly the same second and millisecond.
You can try and expand on this theory by adding day, month or year - that would expand the "seed" exponentially and you will never see repeating sequence of random numbers, but it is extremely hard to do that because once you start playing around with large seed numbers you will encounter weird issues such as if you change a very large number by 1, it would still generate the same sequence of random numbers (in my test scenario, randomizing with any number in the range from 5969992 to 5969995 will result in the same sequence of random numbers: 9, 8, 6, 6, 1). This is probably a limitation of the Randomize function itself. Personally, I don't think its worth trying to go beyond seeding with timer.
Below is your code adjusted to generate a more "random" sequence of numbers:
Dim Num, Random As Integer
Label2.Caption = ""
Num = Val(Text1.Text)
Randomize
Label1.Caption = Int(10 * Rnd + 1)
Random = Val(Label1.Caption)
If Num = Random Then
Label2.Caption = "you won "
Else
Label2.Caption = "The number " & Num & " Does not equal " & Random
End If

dim num, Random as integer
label2.caption =""
num = val(text1.text)
randomize
label1.caption = int((10 +1-1)*rnd+1)
random = val(label1.caption)
if num = random then
label2.caption ="you won"
else
label2.caption = "Try again"
end if

Related

How to check if an item is already in a listbox in vb6

I'm working with vb6 and I want to generate multiple randum numbers (the range from to is detirmend by user and also the number of generated answers) and send them to a listbox
But I don't want to duplicate generated numbers So..
I want before sending the generated number to the listbox to check if it already exists in the lisbox. if it already exists then generate another number if it does't then send it the the listbox
here is what I have till now
max and min are the range to chose numbers between
answers is the number of generated numbers
Randomize
For i = 1 To answers Step 1
generated = CInt(Int((max - min + 1) * Rnd() + min))
For n = 0 To List1.ListCount
If List1.List(n) <> gen Then
List1.AddItem (gen)
Else
If List1.List = gen Then
'I don't know what to do from here
'(how to go back to generate another number)
Next n
Next i
Thank you in advance
keep in minde I need to keep things simple
Thank you soo much
Use a boolean value to keep the result if same value generated is in list.
Private Sub AddRandomNumbers()
Dim blnIfFound As Boolean
Dim max As Integer
Dim min As Integer
Dim answers As Integer
max = 10
min = 1
answers = 5
Randomize
Do While List1.ListCount < answers
generated = CInt(Int((max - min + 1) * Rnd() + min))
blnIfFound = False
For n = 0 To List1.ListCount
If List1.List(n) = generated Then
blnIfFound = True
Exit For
End If
Next n
If blnIfFound = False Then List1.AddItem (generated)
Loop
End Sub

Visual Basic change maker program

I'm working on a program in Visual Basic that takes user input as an integer from 1 to 99 and then tells the use how many quarters, dimes, Nickles, and pennies you need to supplement for that amount. My problem is completely symantical, and my algorithm isn't working like I thought it would. Here is the code that does the actual math, where the variables used are already declared
Select Case Input
Case 25 to 99
numQuarters = Input / 25
remainder = Input Mod 25
Select Case remainder
Case 10 to 24
numDimes = remainder / 10
remainder = remainder mod 10
numNickles = remainder / 5
remainder = remainder mod 5
numPennies = remainder
I'm going to stop there, because that's the only part of the code that's giving me trouble. When I enter a number from 88 to 99 (which is handled by that part of the code) the numbers come out strange. For example, 88 gives me 4 quarters, 1 dime, 1 Nickle, and 3 pennies. I'm not quite sure what's happening, but if someone could help me, I would appreciate it.
I reckon your problem was that it was storing the fractional part of the division, when it should be dropping it and keeping only whole multiples as the fractional portion of each coin is reflected in the remainder.
So after each division, truncate it. E.g.:
numQuarters = Int(Input / 25)
remainder = Input Mod 25
'or since you aren't working with fractional currencies you could use integral division operator '\':
numQuarters = Input \ 25
With 88 as the input it will, after these lines, have numQuarters = 3 and remainder = 18
Anyway, pehaps a more flexible way that doesn't rely on hard-coded orders of precedence and can handle whatever units you like (cents, fractional dollars, whatever) is like:
Sub exampleUsage()
Dim denominations, change
Dim i As Long, txt
'basic UK coins, replace with whatever
'you can of course use pence as the unit, rather than pounds
denominations = Array(1, 0.5, 0.2, 0.1, 0.05, 0.02, 0.01)
change = ChaChing(3.78, denominations)
For i = 0 To UBound(denominations)
txt = txt & Format(denominations(i), "£0.00") & " x " & change(i) & " = " & Format(denominations(i) * change(i), "£0.00") & vbCrLf
Next i
MsgBox (txt)
End Sub
'denominations is a Vector of valid denominations of the amount
'the return is a Vector, corresponding to denominations, of the amount of each denomination
Public Function ChaChing(ByVal money As Double, denominations)
Dim change, i As Long
ReDim change(LBound(denominations) To UBound(denominations))
For i = LBound(denominations) To UBound(denominations)
If money = 0 Then Exit For 'short-circuit
change(i) = Int(money / denominations(i))
money = money - change(i) * denominations(i)
Next i
ChaChing = change
End Function

Combining two lists with minimum distance between elements

I have to lists like these:
a = ["1a","2a","3a","4a","5a","6a","7a","8a","9a","10a","11a","12a","13a","14a"]
b = ["1b","2b","3b","4b","5b","6b","7b","8b","9b","10b","11b","12b","13b","14b"]
And what I want is to combine them, so that there is at least a difference of n elements between an element from a and it's corresponding element in b.
As an example, if my n is 10, and "3a" is in position 3 and "3b" is in position 5, that isn't a solution since there's only a distance of 2 between these corresponding elements.
I have already solved this for the purpose I want through a brute force method: shuffle the union of the two arrays and see if the constraint is met; if not, shuffle again and so on... Needless to say, that for 14 elements array, sometimes there is 5 to 10 second computation to yield a solution with a minimum distance of 10. Even though that's kind of ok for what I am looking for, I am curious about how I could solve this in a more optimized way.
I am currently using Python, but code in any language (or pseudo-code) is more than welcomed.
EDIT: The context of this problem is something like a questionnarie, in which around 100 participants are expected to join in. Therefore, I am not necessarily interested in all the solutions, but rather something like the first 100.
Thanks.
For your specific scenario, you could use a randomized approach -- though not as random as what you've already tried. Something like this:
start with a random permutation of the items in both lists
create a new permutation by creating a copy of the other and randomly swapping two items
measure the quality of the permutations, e.g., the sum of the distances of each pair of related items, or the minimum of such distances
if the quality of the new permutation is better than that of the original permutation, keep the new one, otherwise discard the new one and continue with the original permutation
repeat from 2. until each distance is at least 10 or until quality does not improve over a number of iterations
The difference to shuffling the whole list in each iteration (as in your approach) is that in each iteration the permutation can only get better, until a satisfying solution is found.
Each time you run this algorithm, the result will be slightly different, so you can run it 100 times for 100 different solutions. Of course, this algorithm does not guarantee to find a solution (much less all such solutions), but it should be fast enough so that you could just restart it in case it fails.
In Python, this could look somewhat like this (slightly simplified, but still working):
def shuffle(A, B):
# original positions, i.e. types of questions
kind = dict([(item, i) for i, item in list(enumerate(A)) + list(enumerate(B))])
# get positions of elements of kinds, and return sum of their distances
def quality(perm):
pos = dict([(kind[item], i) for i, item in enumerate(perm)])
return sum(abs(pos[kind[item]] - i) for i, item in enumerate(perm))
# initial permutation and quality
current = A + B
random.shuffle(current)
best = quality(current)
# improve upon initial permutation by randomly swapping items
for g in range(1000):
i = random.randint(0, len(current)-1)
j = random.randint(0, len(current)-1)
copy = current[:]
copy[i], copy[j] = copy[j], copy[i]
q = quality(copy)
if q > best:
current, best = copy, q
return current
Example output for print shuffle(a, b):
['14b', '2a', '13b', '3a', '9b', '4a', '6a', '1a', '8a', '5b', '12b', '11a', '10b', '7b', '4b', '11b', '5a', '7a', '8b', '12a', '13a', '14a', '1b', '2b', '3b', '6b', '10a', '9a']
As I understand from your question, it is possible to perform all the ordering by relying exclusively on the indices of the arrays (i.e., on pure integers) and thus the problem can be reduced to create (valid) ranges instead of analysing each element.
for each a <= total_items-n , valid b = if(a + n == total_items){total_items} else{[a + n, total_items]}
For example:
n = 10;
total_items = 15;
for a = 1 -> valid b = [11, 15]
for a = 2 -> valid b = [12, 15]
, etc.
This would be perfomed 4 times: forwards and backwards for a respect to b and the same for b respect to a.
In this way you would reduce the number of iterations to its minimum expression and would get, as an output, a set of "solutions" for each position, rather than a one-to-one binding (that is what you have right now, isn't it?).
If there are equivalents in Python to .NET's Lists and LINQ, then you may be able to directly convert the following code. It generates up to 100 lists really quickly: I press "debug" to run it and up pops a windows with the results in much less than a second.
' VS2012
Option Infer On
Module Module1
Dim minDistance As Integer = 10
Dim rand As New Random ' a random number generator
Function OkToAppend(current As List(Of Integer), x As Integer) As Boolean
' see if the previous minDistance values contain the number x
Return Not (current.Skip(current.Count - minDistance).Take(minDistance).Contains(x))
End Function
Function GenerateList() As List(Of String)
' We don't need to start with strings: integers will make it faster.
' The "a" and "b" suffixes can be sprinkled on at random once the
' list is created.
Dim numbersToUse() As Integer = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
Dim pool As New List(Of Integer)
' we need all the numbers twice
pool.AddRange(numbersToUse)
pool.AddRange(numbersToUse)
Dim newList As New List(Of Integer)
Dim pos As Integer
For i = 0 To pool.Count - 1
' limit the effort it puts in
Dim sanity As Integer = pool.Count * 10
Do
pos = rand.Next(0, pool.Count)
sanity -= 1
Loop Until OkToAppend(newList, pool(pos)) OrElse sanity = 0
If sanity > 0 Then ' it worked
' append the value to the list
newList.Add(pool(pos))
' remove the value which has been used
pool.RemoveAt(pos)
Else ' give up on this arrangement
Return Nothing
End If
Next
' Create the final list with "a" and "b" stuck on each value.
Dim stringList As New List(Of String)
Dim usedA(numbersToUse.Length) As Boolean
Dim usedB(numbersToUse.Length) As Boolean
For i = 0 To newList.Count - 1
Dim z = newList(i)
Dim suffix As String = ""
If usedA(z) Then
suffix = "b"
ElseIf usedB(z) Then
suffix = "a"
End If
' rand.Next(2) generates an integer in the range [0,2)
If suffix.Length = 0 Then suffix = If(rand.Next(2) = 1, "a", "b")
If suffix = "a" Then
usedA(z) = True
Else
usedB(z) = True
End If
stringList.Add(z.ToString & suffix)
Next
Return stringList
End Function
Sub Main()
Dim arrangements As New List(Of List(Of String))
For i = 1 To 100
Dim thisArrangement = GenerateList()
If thisArrangement IsNot Nothing Then
arrangements.Add(thisArrangement)
End If
Next
'TODO: remove duplicate entries and generate more to make it up to
' the required quantity.
For Each a In arrangements
' outputs the elements of a with ", " as a separator
Console.WriteLine(String.Join(", ", a))
Next
' wait for user to press enter
Console.ReadLine()
End Sub
End Module

How to get values in reverse with loops

The issue is with the bottom of my code where I have to get the program to recite the entered values in reverse order. I think it might be something to do with the index?
Option Explicit On
Option Strict On
'Author: Murray Spears
'Date: October 12th 2012
'Write a program that accepts five input values and stores them into an array.
'Then display numbers in reverse order.
'Then display the average number, and all numbers that are are above average.
Imports System
Module Values
Sub Main()
Dim Number(4) as Integer
Dim Average as Double = 0
Dim Index as integer
'
For Index = 0 to 4
Console.Write("Enter number: ")
Number(Index)=Convert.ToInt32(Console.Readline())
Next Index
'Figure out the average for all the entered values.
Average = (Number(0)+Number(1)+Number(2)+Number(3)+Number(4))/5
Console.Writeline("The average of the numbers is: " &Average)
Console.Write("Numbers that are greater than the average: ")
Index = 4
Do until Index = 0
If Number(Index) > Average then
Console.Writeline(Number(Index))
End If
Index -=1
Loop
Console.Writeline("Numbers in reverse order: ")
Index = 4
Do while Number(index) > 0
Console.Writeline(Number(Index))
Number(index) -= 1
Loop
End Sub
End Module
Use Step -1 to step backwards.
For Index = 4 To 0 Step -1
' do your thing
Next
Imo, the simplest way is to just use a loop as you did when you entered the numbers but as you wrote yourself make the indexes go in reverse.
This is what the "Step -1" is for.
For Index As Integer = 4 To 0 Step -1
Console.Writeline(Number(Index))
Next

Adding values in various combinations

Not sure how best to explain it, other than using an example...
Imagine having a client with 10 outstanding invoices, and one day they provide you with a cheque, but do not tell you which invoices it's for.
What would be the best way to return all the possible combination of values which can produce the required total?
My current thinking is a kind of brute force method, which involves using a self-calling function that runs though all the possibilities (see current version).
For example, with 3 numbers, there are 15 ways to add them together:
A
A + B
A + B + C
A + C
A + C + B
B
B + A
B + A + C
B + C
B + C + A
C
C + A
C + A + B
C + B
C + B + A
Which, if you remove the duplicates, give you 7 unique ways to add them together:
A
A + B
A + B + C
A + C
B
B + C
C
However, this kind of falls apart after you have:
15 numbers (32,767 possibilities / ~2 seconds to calculate)
16 numbers (65,535 possibilities / ~6 seconds to calculate)
17 numbers (131,071 possibilities / ~9 seconds to calculate)
18 numbers (262,143 possibilities / ~20 seconds to calculate)
Where, I would like this function to handle at least 100 numbers.
So, any ideas on how to improve it? (in any language)
This is a pretty common variation of the subset sum problem, and it is indeed quite hard. The section on the Pseudo-polynomial time dynamic programming solution on the page linked is what you're after.
This is strictly for the number of possibilities and does not consider overlap. I am unsure what you want.
Consider the states that any single value could be at one time - it could either be included or excluded. That is two different states so the number of different states for all n items will be 2^n. However there is one state that is not wanted; that state is when none of the numbers are included.
And thus, for any n numbers, the number of combinations is equal to 2^n-1.
def setNumbers(n): return 2**n-1
print(setNumbers(15))
These findings are very closely related to combinations and permutations.
Instead, though, I think you may be after telling whether given a set of values any combination of them sum to a value k. For this Bill the Lizard pointed you in the right direction.
Following from that, and bearing in mind I haven't read the whole Wikipedia article, I propose this algorithm in Python:
def combs(arr):
r = set()
for i in range(len(arr)):
v = arr[i]
new = set()
new.add(v)
for a in r: new.add(a+v)
r |= new
return r
def subsetSum(arr, val):
middle = len(arr)//2
seta = combs(arr[:middle])
setb = combs(arr[middle:])
for a in seta:
if (val-a) in setb:
return True
return False
print(subsetSum([2, 3, 5, 8, 9], 8))
Basically the algorithm works as this:
Splits the list into 2 lists of approximately half the length. [O(n)]
Finds the set of subset sums. [O(2n/2 n)]
Loops through the first set of up to 2floor(n/2)-1 values seeing if the another value in the second set would total to k. [O(2n/2 n)]
So I think overall it runs in O(2n/2 n) - still pretty slow but much better.
Sounds like a bin packing problem. Those are NP-complete, i.e. it's nearly impossible to find a perfect solution for large problem sets. But you can get pretty close using heuristics, which are probably applicable to your problem even if it's not strictly a bin packing problem.
This is a variant on a similar problem.
But you can solve this by creating a counter with n bits. Where n is the amount of numbers. Then you count from 000 to 111 (n 1's) and for each number a 1 is equivalent to an available number:
001 = A
010 = B
011 = A+B
100 = C
101 = A+C
110 = B+C
111 = A+B+C
(But that was not the question, ah well I leave it as a target).
It's not strictly a bin packing problem. It's a what combination of values could have produced another value.
It's more like the change making problem, which has a bunch of papers detailing how to solve it. Google pointed me here: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.57.3243
I don't know how often it would work in practice as there are many exceptions to this oversimplified case, but here's a thought:
In a perfect world, the invoices are going to be paid up to a certain point. People will pay A, or A+B, or A+B+C, but not A+C - if they've received invoice C then they've received invoice B already. In the perfect world the problem is not to find to a combination, it's to find a point along a line.
Rather than brute forcing every combination of invoice totals, you could iterate through the outstanding invoices in order of date issued, and simply add each invoice amount to a running total which you compare with the target figure.
Back in the real world, it's a trivially quick check you can do before launching into the heavy number-crunching, or chasing them up. Any hits it gets are a bonus :)
Here is an optimized Object-Oriented version of the exact integer solution to the Subset Sums problem(Horowitz, Sahni 1974). On my laptop (which is nothing special) this vb.net Class solves 1900 subset sums a second (for 20 items):
Option Explicit On
Public Class SubsetSum
'Class to solve exact integer Subset Sum problems'
''
' 06-sep-09 RBarryYoung Created.'
Dim Power2() As Integer = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32764}
Public ForceMatch As Boolean
Public watch As New Stopwatch
Public w0 As Integer, w1 As Integer, w1a As Integer, w2 As Integer, w3 As Integer, w4 As Integer
Public Function SolveMany(ByVal ItemCount As Integer, ByVal Range As Integer, ByVal Iterations As Integer) As Integer
' Solve many subset sum problems in sequence.'
''
' 06-sep-09 RBarryYoung Created.'
Dim TotalFound As Integer
Dim Items() As Integer
ReDim Items(ItemCount - 1)
'First create our list of selectable items:'
Randomize()
For item As Integer = 0 To Items.GetUpperBound(0)
Items(item) = Rnd() * Range
Next
For iteration As Integer = 1 To Iterations
Dim TargetSum As Integer
If ForceMatch Then
'Use a random value but make sure that it can be matched:'
' First, make a random bitmask to use:'
Dim bits As Integer = Rnd() * (2 ^ (Items.GetUpperBound(0) + 1) - 1)
' Now enumerate the bits and match them to the Items:'
Dim sum As Integer = 0
For b As Integer = 0 To Items.GetUpperBound(0)
'build the sum from the corresponding items:'
If b < 16 Then
If Power2(b) = (bits And Power2(b)) Then
sum = sum + Items(b)
End If
Else
If Power2(b - 15) * Power2(15) = (bits And (Power2(b - 15) * Power2(15))) Then
sum = sum + Items(b)
End If
End If
Next
TargetSum = sum
Else
'Use a completely random Target Sum (low chance of matching): (Range / 2^ItemCount)'
TargetSum = ((Rnd() * Range / 4) + Range * (3.0 / 8.0)) * ItemCount
End If
'Now see if there is a match'
If SolveOne(TargetSum, ItemCount, Range, Items) Then TotalFound += 1
Next
Return TotalFound
End Function
Public Function SolveOne(ByVal TargetSum As Integer, ByVal ItemCount As Integer _
, ByVal Range As Integer, ByRef Items() As Integer) As Boolean
' Solve a single Subset Sum problem: determine if the TargetSum can be made from'
'the integer items.'
'first split the items into two half-lists: [O(n)]'
Dim H1() As Integer, H2() As Integer
Dim hu1 As Integer, hu2 As Integer
If ItemCount Mod 2 = 0 Then
'even is easy:'
hu1 = (ItemCount / 2) - 1 : hu2 = (ItemCount / 2) - 1
ReDim H1((ItemCount / 2) - 1), H2((ItemCount / 2) - 1)
Else
'odd is a little harder, give the first half the extra item:'
hu1 = ((ItemCount + 1) / 2) - 1 : hu2 = ((ItemCount - 1) / 2) - 1
ReDim H1(hu1), H2(hu2)
End If
For i As Integer = 0 To ItemCount - 1 Step 2
H1(i / 2) = Items(i)
'make sure that H2 doesnt run over on the last item of an odd-numbered list:'
If (i + 1) <= ItemCount - 1 Then
H2(i / 2) = Items(i + 1)
End If
Next
'Now generate all of the sums for each half-list: [O( 2^(n/2) * n )] **(this is the slowest step)'
Dim S1() As Integer, S2() As Integer
Dim sum1 As Integer, sum2 As Integer
Dim su1 As Integer = 2 ^ (hu1 + 1) - 1, su2 As Integer = 2 ^ (hu2 + 1) - 1
ReDim S1(su1), S2(su2)
For i As Integer = 0 To su1
' Use the binary bitmask of our enumerator(i) to select items to use in our candidate sums:'
sum1 = 0 : sum2 = 0
For b As Integer = 0 To hu1
If 0 < (i And Power2(b)) Then
sum1 += H1(b)
If i <= su2 Then sum2 += H2(b)
End If
Next
S1(i) = sum1
If i <= su2 Then S2(i) = sum2
Next
'Sort both lists: [O( 2^(n/2) * n )] **(this is the 2nd slowest step)'
Array.Sort(S1)
Array.Sort(S2)
' Start the first half-sums from lowest to highest,'
'and the second half sums from highest to lowest.'
Dim i1 As Integer = 0, i2 As Integer = su2
' Now do a merge-match on the lists (but reversing S2) and looking to '
'match their sum to the target sum: [O( 2^(n/2) )]'
Dim sum As Integer
Do While i1 <= su1 And i2 >= 0
sum = S1(i1) + S2(i2)
If sum < TargetSum Then
'if the Sum is too low, then we need to increase the ascending side (S1):'
i1 += 1
ElseIf sum > TargetSum Then
'if the Sum is too high, then we need to decrease the descending side (S2):'
i2 -= 1
Else
'Sums match:'
Return True
End If
Loop
'if we got here, then there are no matches to the TargetSum'
Return False
End Function
End Class
Here is the Forms code to go along with it:
Public Class frmSubsetSum
Dim ssm As New SubsetSum
Private Sub btnGo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGo.Click
Dim Total As Integer
Dim datStart As Date, datEnd As Date
Dim Iterations As Integer, Range As Integer, NumberCount As Integer
Iterations = CInt(txtIterations.Text)
Range = CInt(txtRange.Text)
NumberCount = CInt(txtNumberCount.Text)
ssm.ForceMatch = chkForceMatch.Checked
datStart = Now
Total = ssm.SolveMany(NumberCount, Range, Iterations)
datEnd = Now()
lblStart.Text = datStart.TimeOfDay.ToString
lblEnd.Text = datEnd.TimeOfDay.ToString
lblRate.Text = Format(Iterations / (datEnd - datStart).TotalMilliseconds * 1000, "####0.0")
ListBox1.Items.Insert(0, "Found " & Total.ToString & " Matches out of " & Iterations.ToString & " tries.")
ListBox1.Items.Insert(1, "Tics 0:" & ssm.w0 _
& " 1:" & Format(ssm.w1 - ssm.w0, "###,###,##0") _
& " 1a:" & Format(ssm.w1a - ssm.w1, "###,###,##0") _
& " 2:" & Format(ssm.w2 - ssm.w1a, "###,###,##0") _
& " 3:" & Format(ssm.w3 - ssm.w2, "###,###,##0") _
& " 4:" & Format(ssm.w4 - ssm.w3, "###,###,##0") _
& ", tics/sec = " & Stopwatch.Frequency)
End Sub
End Class
Let me know if you have any questions.
For the record, here is some fairly simple Java code that uses recursion to solve this problem. It is optimised for simplicity rather than performance, although with 100 elements it seems to be quite fast. With 1000 elements it takes dramatically longer, so if you are processing larger amounts of data you could better use a more sophisticated algorithm.
public static List<Double> getMatchingAmounts(Double goal, List<Double> amounts) {
List<Double> remaining = new ArrayList<Double>(amounts);
for (final Double amount : amounts) {
if (amount > goal) {
continue;
} else if (amount.equals(goal)) {
return new ArrayList<Double>(){{ add(amount); }};
}
remaining.remove(amount);
List<Double> matchingAmounts = getMatchingAmounts(goal - amount, remaining);
if (matchingAmounts != null) {
matchingAmounts.add(amount);
return matchingAmounts;
}
}
return null;
}

Resources