Nested Loops and Conditional stuff

Blitz3D Forums/Blitz3D Beginners Area/Nested Loops and Conditional stuff

CyberPackRat(Posted 2012) [#1]
I am rewriting a program to make it more versatile. Basically it iterates through every possible combination in a lottery pick 5 game to derive various stats that I wish to check out.

Is there a way to code something that will expand to a pick 6 game instead writing another program just for that purpose?

Here are two nested loops. Currently I use the For/Next one
I was thinking a Repeat/Until would probably be a step in the right direction.

This is just a pet project of mine, so no, I don't believe there is a system that will give the winning numbers. (But if I could, I would hire Mark Sibly and pay him a crazy amount of cash).

HighBall = 39

For b1 = 1 To HighBall-4
	For b2 = b1+1 To HighBall-3
		For b3 = b2+1 To HighBall-2
			For b4 = b3+1 To HighBall-1
				For b5 = b4+1 To HighBall
				
					Total = Total + 1
					
				Next
			Next
		Next
	Next
Next 

Print total

WaitKey



HighBall = 39

b1 = 1
Repeat
	b2 = b1 + 1
	Repeat
		b3 = b2 + 1
		Repeat 
			b4 = b3 + 1	
			Repeat
				b5 = b4 + 1
				Repeat

					total = total + 1
					b5 = b5 + 1

				Until b5 > HighBall - 0
				b4 = b4 + 1
			Until b4 > HighNum - 1
			b3 = b3 + 1
		Until b3 > HighNum - 2
		b2 = b2 + 1
	Until b2 > HighNum - 3
	b1 = b1 + 1
Until b1 > HighNum  - 4

Print Total

WaitKey


Last edited 2012


Guy Fawkes(Posted 2012) [#2]
I think this belongs in the code archives


CyberPackRat(Posted 2012) [#3]
I wasn't finished... I was copying and pasting code... then wrote the message afterwards (making sure the code blocks displayed properly. <grin>


But now that I have your attention Bwa-Ha-Ha... any ideas how to do this ?!

Last edited 2012


Yasha(Posted 2012) [#4]
Now how is the Repeat/Until loop an improvement on the first code? All you've done is make it bigger, separating the looping conditions onto multiple lines at both ends of the block. It takes up more space and it's harder to read.

The only obvious way to do something like this and make the number of nested loops flexible is to use recursion (i.e. a function). That way you can keep a count of how many times you've entered the looping construct with an accumulator parameter, and decide whether to nest further or not.

It's more or less impossible to have variable-depth nesting of code without using functions, since functions are the only way for the same area of code to be "active" on more than one layer (at best, using "flat" code, you could set a maximum depth of nested loops by writing all of them out by hand... but this is a lot of writing and it's still nowhere near as powerful).

Last edited 2012


CyberPackRat(Posted 2012) [#5]
Thanks for responding Yasha.

Yeah, I understand both sets of code are the doing the same thing. What I was getting at could/should the Repeat/Until version (in all its ugliness) be expanded upon to accomplish what i am after?

As you say though, not the right approach.

I figured recursion would honestly be the way to go, but I have never really done any work on that and so I have very little knowledge on the matter. Just a hobbyist I am afraid when it comes to programming. No real schooling.

I would be extremely grateful though if you or anyone could show me how to accomplish it.


Yasha(Posted 2012) [#6]
If I understand correctly what you want to do, try this:

Print CountBalls(1, 39, 5)
WaitKey


Function CountBalls(lowBall, highBall, numBalls)
	Local b, total
	For b = lowBall To highBall - (numBalls - 1)
		If numBalls > 1
			total = total + CountBalls(b + 1, highBall, numBalls - 1)
		Else
			total = total + 1
		EndIf
	Next
	Return total
End Function


As you can see, one single loop actually written out, but can go to any depth by altering the numBalls parameter (note: cannot go to any depth in practice, will probably crash above a couple of hundred), because it can decide whether to go deeper or not rather than being locked into a given nesting structure.


CyberPackRat(Posted 2012) [#7]
Will check it out. Thank you !!


CyberPackRat(Posted 2012) [#8]
Indeed, that is expandable.


Now with my previous loop, I do silly things like the following:

Target = 1

HighBall = 39

For b1 = 1 To HighBall-4
	For b2 = b1+1 To HighBall-3
		For b3 = b2+1 To HighBall-2
			For b4 = b3+1 To HighBall-1
				For b5 = b4+1 To HighBall
				
					Total = Total + 1

					If b1 = target Then TargetTally = TargetTally + 1 
					If b2 = target Then TargetTally = TargetTally + 1 
					If b3 = target Then TargetTally = TargetTally + 1 
					If b4 = target Then TargetTally = TargetTally + 1 
					If b5 = target Then TargetTally = TargetTally + 1 
					
				Next
			Next
		Next
	Next
Next 

Print "The #" + Target + " appears in " + TargetTally + " out of " + Total + " combinations."

WaitKey


What the above does is that it counts for how many times a particular number, in this instance the number 1, appears in the each sequence of combinations.

Can I still do things like that?

Other stuff the program does is count Gap Patterns in each combo by subtracting b2-b1 for first Gap, b3-b2 for the 2nd, b4-b3 for the 3rd, and b5-b4 for the 4th. So that 5,10,12,19,30 would be 5,2,7,21.

The actual code is VERY ugly. It would give you nightmares.

Last edited 2012


CyberPackRat(Posted 2012) [#9]
I guess what I am saying in a round way, is I need to be able to check each combination's individual numbers to test for various things but I would like the iteration part to be flexible to fit different types of lotteries.

I hope I am not being a pain, and let me state once more I *TRULY* appreciate your time and help here.

Last edited 2012


CyberPackRat(Posted 2012) [#10]
My first attempt at a recursive function.
Maybe not quite way you would go about it but here it is anyways:

A little Fibonacci.


Fibonacci(0, 1, 20)
WaitKey


Function Fibonacci(Num1, Num2, Seq)
	If Seq > 1
		total = Num1 + Num2
		Fibonacci(Num2, total, Seq -1)
	End If
	Print Num1 
End Function


Last edited 2012


Yasha(Posted 2012) [#11]
...there are a few ways you can expand the code as above to do those sorts of things, but depending on how many other strange and various tests you need to do, it may be better to simply devise a different function to get each test value individually.

You can't do a straight rewrite of the TargetTally code quite as easily as the Total code, because the TotalTally version wants information from the outer loops in the innermost one. This isn't directly possible in the same way as the "flat" code because of Blitz's local scoping rules (you'd need something like "dynamic scope" for that). So you'll need to modify the algorithm slightly.

In this case, the simplest thing to notice is that although each check needs to be in the innermost loop to increment the right number of times, it doesn't actually use any information from any deeper than the loop whose iterator it uses as its check. So, you can pull it out and instead multiply it by the relevant number of iterations of the inner loop. You can also observe that the target number can actually only appear once in each loop (so a loop isn't necessary at all), and that it will appear in a combination once it's been found the first time, meaning testing for it in the deeper loops is unnecessary as we can simply multiply by how many of them will occur instead...


So yeah. I think a refactor might be quite a bit better.


If you are interested in learning some slightly more formal stuff about algorithms, I should take a moment to (yet again) shill the wonderful book Structure and Interpretation of Computer Programs, available to read for free on the MIT website. Goes into great detail on subjects like recursion and scope.


EDIT: As for the Fibonacci function... great! If this is your first time thinking about recursion then you've actually grasped it quite a bit more quickly than most people do! I see you've also got a handle on accumulator-passing (and, you might not have thought about it this way, but you've also demonstrated beautifully there how a recursive tail call is directly equivalent to the jump at the end of a loop).

Last edited 2012


Floyd(Posted 2012) [#12]
The same question came up in 2004. I wrote the following code as my solution. It no longer exists on this site. But a quick rummage through my old CD backups recovered it.

Just replace the Display routine with code that does actual work with current combination in array c().

; Will generate millions of combinations per second on a modest PC.
; The only real time consumed is by the Display function.


Graphics 300, 460, 0, 2

Dim c(0)  ; will hold combinations

GenerateAll 7, 3

WaitKey : End



Function GenerateAll( n, k )    ; All ways to choose k numbers from 1..n
   
   MaxC1 = n - k + 1

   Dim c(k)
   Initialize 1, k, 1

   Repeat
      Display k
      If c(1) = MaxC1 Then Return
      Increment k, n
   Forever

End Function


Function Display( cLast )

   For j = 1 To cLast
      Write RSet( c(j), 3 )
   Next
   Print ""
   Delay 200

End Function

Function Increment( cLast, n )   ; set c() to next valid combination

   j = cLast
   MaxValue = n
   
   Repeat
      If c(j) < MaxValue
         Initialize j, cLast, c(j) + 1
         Return
      End If
      j = j - 1
      MaxValue = MaxValue - 1
   Forever

End Function

Function Initialize( cFirst, cLast, cValue )

   For j = cFirst To cLast
      c(j) = cValue
      cValue = cValue + 1
   Next

End Function


Last edited 2012


CyberPackRat(Posted 2012) [#13]
Hey Floyd. I am viewing this on my phone, but it appears your code is not all there. :(
Very interested in setting that.

Tasha, thanks for kind words, recursion makes my brain ache though. Something just clicked finally and I wanted test something to see if I was "getting it". I will definitely check out your link.

Lots of help today from you guys. Love the Blitz community.



Alright, break time is over. Got to get back to work. Come on 5pm!


Floyd(Posted 2012) [#14]
Hey Floyd. I am viewing this on my phone, but it appears your code is not all there. :(

I see what you mean. It looks like codebox doesn't display properly on my Nook Color, no scroll bars. The code is short enough that it doesn't really matter so I changed it.

Last edited 2012


CyberPackRat(Posted 2012) [#15]
Coolness. Thanx.


CyberPackRat(Posted 2012) [#16]
I reading your code during lunch, and it seems so simple in concept, yet I never would have come up with it myself. Ingenious. Can I just mention again how cool you guys are?

Can't wait to show my son this. Unlike me, he is actually taking computer classes in school so he too will find this interesting and learn something.