|
Post by bplus on Aug 19, 2024 4:13:39 GMT
OK so here is a function that returns 15 random numbers (from 25) in order, it returns it in a string$ which functions can return under their name:
For i = 1 To 20 Print FifteenRandomNumbersInOrder$ Next
Function FifteenRandomNumbersInOrder$ () Dim deckOfNumbers(25) As Integer For i = 1 To 25 deckOfNumbers(i) = i Next For i = 25 To 2 Step -1 Swap deckOfNumbers(i), deckOfNumbers(Int(Rnd * i) + 1) Next For i = 1 To 25 For j = 1 To 15 ' look at only 1st 15 numbers of deck If deckOfNumbers(j) = i Then rtn$ = rtn$ + Str$(deckOfNumbers(j)) count = count + 1 If count = 15 Then FifteenRandomNumbersInOrder$ = rtn$ Exit Function End If End If Next Next End Function
We do all the array stuff inside the function so don't need any arrays going in or out!
|
|
|
Post by carlos45 on Aug 19, 2024 4:28:09 GMT
The SUB works, Bplus. I was so focused on the function that I didn't send the debug or the image. I apologize for my mistake. Carlos Const False = 0 Const True = Not False
Dim i As Integer 'ReDim Shared deckOfNumbers(1 To 25) As Integer ReDim Shared numeros(1 To 15) As Integer ReDim Shared deckOfNumbers(1 To 25) As Integer
Dim TempArray(1 To 15) As Integer ReDim TempJogos(1 To 2, 1 To 15) As Integer Open "Debug_SUB.txt" For Output As #1
For i = 1 To 2
GerarNumerosRND numeros()
For k = 1 To 15 TempJogos(i, k) = numeros(k)
Print #1, "Number calls function"; k; ": "; TempJogos(i, k)
Print TempJogos(i, k), k Sleep Next k Next i Sub GerarNumerosRND (numeros() As Integer) 'Dim deckOfNumbers(25) As Integer Dim order(25) As Integer Dim i As Integer, e As Integer
Dim count As Integer
For i = 1 To 25 deckOfNumbers(i) = i Next For i = 25 To 2 Step -1 Swap deckOfNumbers(i), deckOfNumbers(Int(Rnd * i) + 1) Next
ReDim order(1 To 25) As Integer For i = 1 To 15 order(deckOfNumbers(i)) = True Next count = 0
For e = 1 To 25 If order(e) Then count = count + 1 numeros(count) = e End If Next End Sub Attachments:Debug_SUB.txt (958 B)
|
|
|
Post by bplus on Aug 19, 2024 4:31:31 GMT
Yeah I saw that the sub worked, so does my Function!
|
|
|
Post by carlos45 on Aug 19, 2024 4:51:40 GMT
I know, Bplus, that your function works perfectly. I just didn't want to use a string and then, when calling the function, extract the numbers into an array. Since the other forum, I realized that you always like to analyze and find anomalies in the codes. Please see what is happening with my code, because it is defying what you made very clear: even though I know that I cannot pass arrays as arguments to functions nor return arrays directly, as in FunctionName = Array(), the code is presenting a strange behavior. It seems that the array deckOfNumbers is being updated and accessed correctly, as if the function could return the array directly. I tried calling the function with GenerateNumbersdeck = deckOfNumbers(numbers()), but it continues to call correctly, but out of order. Carlos Const False = 0 Const True = Not False
Dim i As Integer 'ReDim Shared deckOfNumbers(1 To 25) As Integer ReDim Shared numeros(1 To 15) As Integer 'ReDim Shared deckOfNumbers(1 To 25) As Integer
Dim TempArray(1 To 15) As Integer ReDim TempJogos(1 To 2, 1 To 15) As Integer Open "Debug.txt" For Output As #1
For i = 1 To 2
For k = 1 To 15 ' TempArray = GerarNumerosdeck(i) TempJogos(i, k) = GerarNumerosdeck(k) Print #1, "Number calls function"; k; ": "; TempJogos(i, k) Print TempJogos(i, k), k Sleep Next k Print #1, "" Next i Close #1
Function GerarNumerosdeck (numeros As Integer) Randomize Timer Dim deckOfNumbers(25) As Integer Dim i As Integer, e As Integer Dim count As Integer
For i = 1 To 25 deckOfNumbers(i) = i Next For i = 25 To 2 Step -1 Swap deckOfNumbers(i), deckOfNumbers(Int(Rnd * i) + 1) Next ReDim order(1 To 25) As Integer For i = 1 To 15 order(deckOfNumbers(i)) = True Next count = 0
For e = 1 To 25 If order(e) Then count = count + 1 numeros(count) = e End If Next For i = 1 To 15 ' Print #1, "Number inside the function "; i; " : "; numeros(i) Next i GerarNumerosdeck = deckOfNumbers(numeros()) ' MyFunctionToldMe& = MyFunction&(myArrayIPassedToMyFunction())
End Function
Attachments:
Debug.txt (967 B)
|
|
|
Post by bplus on Aug 19, 2024 5:07:00 GMT
I already said this line is never going to work in QB64: GerarNumerosdeck = deckOfNumbers(numeros()) what is that anyway an array within an array??? whew!
You CAN NOT ASSIGN AN Array to the Function name to return back to the main code, it has to be a type that has a suffix or default no suffix = Single Type.
I don't know why the compiler is NOT telling you about the error??? It must be a bug in QB64.
Assigning a value to the Function name for it to return in the code that called it is NOT the same as passing Arrays as arguments, not at all.
YOU CAN PASS ARRAYS TO FUNCTIONS AS ARGUMENTS! How many times are you going to make me repeat that?
|
|
|
Post by bplus on Aug 19, 2024 5:15:58 GMT
I have generalized the function to do N numbers of OfM Numbers:
For i = 1 To 20 Print NOfMRandomNumbersInOrder$(Int(Rnd * 11) + 5, Int(Rnd * 21) + 15) Next
Function NOfMRandomNumbersInOrder$ (N, OfM) Dim deck(OfM) As Integer For i = 1 To OfM deck(i) = i Next For i = OfM To 2 Step -1 Swap deck(i), deck(Int(Rnd * i) + 1) Next For i = 1 To OfM For j = 1 To N ' look at only 1st 15 of deck If deck(j) = i Then rtn$ = rtn$ + Str$(deck(j)) count = count + 1 If count = N Then NOfMRandomNumbersInOrder$ = rtn$ Exit Function End If End If Next Next End Function
|
|
|
Post by bplus on Aug 19, 2024 5:46:21 GMT
OK a Function with an Array Output, what goes in comes out changed!
_Title "15 of 25 Random Numbers in Order - It's Just Gotta be a Function!" ' b+ 2024-08-19 :D Const True = -1 Dim FillMeIN(1 To 15) As Integer While _KeyDown(27) = 0 Dummy$ = GerarNumerosdeck$(FillMeIN()) For j = 1 To 15 Print j; FillMeIN(j) Next Print: Print "esc to quit, press any to see another... " Sleep Cls Wend
Function GerarNumerosdeck$ (LoadMeUp() As Integer) Randomize Timer Dim deckOfNumbers(1 To 25) As Integer Dim Numeros(1 To 25) As Integer Dim i As Integer, e As Integer Dim count As Integer
For i = 1 To 25 deckOfNumbers(i) = i Next For i = 25 To 2 Step -1 Swap deckOfNumbers(i), deckOfNumbers(Int(Rnd * i) + 1) Next ReDim order(1 To 25) As Integer For i = 1 To 15 order(deckOfNumbers(i)) = True Next count = 0 For e = 1 To 25 If order(e) Then count = count + 1 Numeros(count) = e End If Next For i = 1 To 15 'Print "Number inside the function "; i; " : "; Numeros(i) LoadMeUp(i) = Numeros(i) Next i
' because someone insists this be a Function!!! GerarNumerosdeck$ = "This doesn't matter, it's a dummy string to return." End Function
|
|
|
Post by bplus on Aug 19, 2024 13:06:00 GMT
OK in attempts to clear up any confusion I may have caused carlos45 I am posted my edit and EDIT 2 here to make sure it is not missed. Originally I said misleadingly: "You can't pass arrays through Function in QB64." I think this was place where Carlos got the wrong idea that I said you can't pass arrays as arguments to a function. That was poorly worded and I apologize. I meant to say you can't assign arrays to the function name for the function to return in the calling code.
|
|
|
Post by bplus on Aug 19, 2024 17:31:33 GMT
Oh BTW, here it is in Sub form all we did was eliminate the dummy$ = Function(array()) and just call the Sub
And we eliminate the silly dummy string assigned to the Function name before returning to code that called routine, way cleaner without BS of Function:
_Title "15 of 25 Random Numbers in Order - It's Just Gotta be a Function!" ' b+ 2024-08-19 :D Const True = -1 Dim FillMeIN(1 To 15) As Integer While _KeyDown(27) = 0 GerarNumerosdeck FillMeIN() For j = 1 To 15 Print j; FillMeIN(j) Next Print: Print "esc to quit, press any to see another... " Sleep Cls Wend
Sub GerarNumerosdeck (LoadMeUp() As Integer) Randomize Timer Dim deckOfNumbers(1 To 25) As Integer Dim Numeros(1 To 25) As Integer Dim i As Integer, e As Integer Dim count As Integer
For i = 1 To 25 deckOfNumbers(i) = i Next For i = 25 To 2 Step -1 Swap deckOfNumbers(i), deckOfNumbers(Int(Rnd * i) + 1) Next ReDim order(1 To 25) As Integer For i = 1 To 15 order(deckOfNumbers(i)) = True Next count = 0 For e = 1 To 25 If order(e) Then count = count + 1 Numeros(count) = e End If Next For i = 1 To 15 'Print "Number inside the function "; i; " : "; Numeros(i) LoadMeUp(i) = Numeros(i) Next i End Sub
|
|
|
Post by carlos45 on Aug 19, 2024 21:39:41 GMT
Bplus, you don't need to apologize; after all, I'm the one asking for help, and you're doing your best. You're absolutely right when you say: 'I meant that you can't assign arrays to the function name so that the function returns in the calling code.' I've been analyzing some functions and I realized that none of them involve arrays to be called. Now, about this function you created, I liked it and I'm going to make some changes and post it here. I'd like your opinion if I can use this change without any problems. I'm going to save all these functions. Carlos Attachments:
|
|
|
Post by carlos45 on Aug 19, 2024 22:51:01 GMT
Bplus, once again, I just want to thank you. Thank you very much for your dedication. I made a small change, adding % to the end of the function name to indicate an integer return type, because I really liked the function. As I said before, I will gradually migrate all my codes to SUBs and functions. I will not praise you any more so as not to give the impression of flattery. Until next time, my friend. Carlos _Title "15 of 25 Random Numbers in Order - It's Just Gotta be a Function!" ' b+ 2024-08-19 :D Const True = -1 Dim FillMeIN(1 To 15) As Integer While _KeyDown(27) = 0 Dummy = GerarNumerosdeck%(FillMeIN()) For j = 1 To 15 Print j; FillMeIN(j) Sleep Next Print: Print "esc to quit, press any to see another... " Sleep Cls Wend
Function GerarNumerosdeck% (LoadMeUp() As Integer) Randomize Timer Dim deckOfNumbers(1 To 25) As Integer Dim Numeros(1 To 25) As Integer Dim i As Integer, e As Integer Dim count As Integer
For i = 1 To 25 deckOfNumbers(i) = i Next For i = 25 To 2 Step -1 Swap deckOfNumbers(i), deckOfNumbers(Int(Rnd * i) + 1) Next ReDim order(1 To 25) As Integer For i = 1 To 15 order(deckOfNumbers(i)) = True Next count = 0 For e = 1 To 25 If order(e) Then count = count + 1 Numeros(count) = e End If Next For i = 1 To 15 LoadMeUp(i) = Numeros(i) Next i
' because someone insists this be a Function!!! GerarNumerosdeck% = 0 '"This doesn't matter, it's a dummy string to return." End Function
Attachments:
|
|
|
Post by bplus on Aug 20, 2024 6:57:27 GMT
Hi Carlos, since you insist on a Function then I recommend again that it return a String! Even though Functions can't return arrays, they CAN return strings AND you CAN USE a string just like you use arrays! You can insert, edit, append and delete items of a string. They are in fact more flexible than arrays in that you don't have to dimension them ahead of time. Here is the place where I have given you String Tools to be able to treat items in a string like items in an array: qb64.boards.net/thread/277/item-tools-strings-behave-arrays
|
|
|
Post by bplus on Aug 20, 2024 7:31:05 GMT
Here is a little demo of the power of Strings! (and Item$ Tools) _Title "Strings can work better than arrays!!!" ' b+ 2024-08-20 For i = 1 To 20 'Print NOfMRandomNumbersInOrder$(Int(Rnd * 11) + 5, Int(Rnd * 21) + 15)
'get a random string with a random number of numbers in it myStr$ = NOfMRandomNumbersInOrder$(Int(Rnd * 11) + 5, Int(Rnd * 21) + 15)
'we need to _trim$ the leading and ending spaces in the string so we don't over count spaces myStr$ = _Trim$(myStr$)
' the number of items in a string is one more than number of spaces nItems = StrCount&(myStr$, " ") + 1
' now show the string like it were an array!!! Print myStr$ Print "Has"; nItems; "items in it." For i = 1 To nItems Print i; "is "; Item$(myStr$, " ", i) Next Print: Print "zzz, sleeping, press any to continue..." Sleep Cls Next
Function NOfMRandomNumbersInOrder$ (N, OfM) Dim deck(OfM) As Integer For i = 1 To OfM deck(i) = i Next For i = OfM To 2 Step -1 Swap deck(i), deck(Int(Rnd * i) + 1) Next For i = 1 To OfM For j = 1 To N ' look at only 1st 15 of deck If deck(j) = i Then rtn$ = rtn$ + Str$(deck(j)) ' str$(number) always leaves a space between positive numbers count = count + 1 If count = N Then NOfMRandomNumbersInOrder$ = rtn$ Exit Function End If End If Next Next End Function
Function StrCount& (AString$, S$) ' Count S$ in Astring$ ReDim place As Long, cnt As Long, lenS As Long place = InStr(AString$, S$): lenS = Len(S$) While place cnt = cnt + 1 place = InStr(place + lenS, AString$, S$) Wend StrCount& = cnt End Function
Function Item$ (Source$, Delimiter$, Index&) Dim c As Long, d As Long, lastd As Long If Len(Source$) = 0 Then Item$ = "": Exit Function lastd = 1: d = InStr(lastd, Source$, Delimiter$) While d > 0 c = c + 1 If c = Index& Then Item$ = Mid$(Source$, lastd, d - lastd): Exit Function Else lastd = d + 1: d = InStr(lastd, Source$, Delimiter$) End If Wend c = c + 1 If c <> Index& Then Item$ = "" Else Item$ = Mid$(Source$, lastd, Len(Source$)) End Function
Attachments:
|
|
|
Post by carlos45 on Aug 20, 2024 18:57:02 GMT
Bplus, as I said before, I wanted to know your opinion and, of course, I will follow your recommendation for the function to return a string. The example '_Title "Strings can work better than arrays!!!" b+ 2024-08-20' that you posted, I will use in another approach of mine. Once again, Bplus, thanks for the link with a good amount of functions. Lots of material for when I want to adapt it in my codes. Carlos. Attachments:
|
|
|
Post by bplus on Aug 21, 2024 0:28:00 GMT
carlos45 Oh I guess there is an even better way to handle a string from a Function. Using the Split sub you can take a string, specify the delimiter used in it to separate the items and then specify a Dynamic array to load the sub strings into. A Dynamic Array is one that is resizable and is started with REDIM not DIM. I also fixed the Function generating the random N amount of M numbers in Order to _TRIM$ the string the function is to return. I also used order variablke to make more clear what it is doing and to exit For loop when get match to order for more efficient routine. _Title "Split a String into an Array" ' b+ 2024-08-20
ReDim myDigits$(1 To 1) ' setup a Dynamic (resizable) array to split strings into ' using (1 to 1) so the Ubound of the loaded array = number of items in array
While _KeyDown(27) = 0
'get a random string with a random number of numbers in it myStr$ = NOfMRandomNumbersInOrder$(15, 25) ' 15 numbers of 25 numbers
' break the string up into an array of strings Split myStr$, " ", myDigits$()
' now show the string and the array made from it!!! Print myStr$ Print "Has"; UBound(myDigits$); "items in it." For i = 1 To UBound(myDigits$) Print i; "is "; myDigits$(i) Next Print: Print "zzz, sleeping, press any to continue..." Sleep Cls Wend
Function NOfMRandomNumbersInOrder$ (N, OfM) Dim deck(OfM) As Integer For i = 1 To OfM deck(i) = i Next For i = OfM To 2 Step -1 Swap deck(i), deck(Int(Rnd * i) + 1) Next order = 1 While order <= OfM For j = 1 To N ' look at only 1st 15 of deck If deck(j) = order Then rtn$ = rtn$ + Str$(deck(j)) ' str$(number) always leaves a space between positive numbers count = count + 1 If count = N Then NOfMRandomNumbersInOrder$ = _Trim$(rtn$) ' remove spaces at start or end of string Exit Function Else Exit For ' a little more efficient to skip out pf For loop End If End If Next order = order + 1 Wend End Function
' this sub requires the loadMeArray() to be Dynamic ie REDIM loadMeArray(1 to 1) as string Sub Split (SplitMeString As String, delim As String, loadMeArray() As String) Dim curpos As Long, arrpos As Long, LD As Long, dpos As Long 'fix use the Lbound the array already has curpos = 1: arrpos = LBound(loadMeArray): LD = Len(delim) dpos = InStr(curpos, SplitMeString, delim) Do Until dpos = 0 loadMeArray(arrpos) = Mid$(SplitMeString, curpos, dpos - curpos) arrpos = arrpos + 1 If arrpos > UBound(loadMeArray) Then ReDim _Preserve loadMeArray(LBound(loadMeArray) To UBound(loadMeArray) + 1000) As String curpos = dpos + LD dpos = InStr(curpos, SplitMeString, delim) Loop loadMeArray(arrpos) = Mid$(SplitMeString, curpos) ReDim _Preserve loadMeArray(LBound(loadMeArray) To arrpos) As String 'get the ubound correct End Sub
We get the same results as before but maybe more directly.
|
|