Omnimaga

Calculator Community => TI Calculators => TI-BASIC => Topic started by: Builderboy on January 23, 2010, 01:31:57 am

Title: In-Program Sub-Routines
Post by: Builderboy on January 23, 2010, 01:31:57 am
So this is a small bit of code that takes advantage of Memory leaks in order to run 'Sub-Routines' that you can place within your programs!  This can be advantageous for people who want to compile their games into a single program to clear up Program menus

Code: [Select]
Goto M                        //Start of Subroutine section.  We want it to be at the top of the program, as all subroutines are accessed via lables
                              //This code is skipped due to the Goto M statement
Lbl A                         //Subroutine A
Disp "This is a fun sub"
Disp "Its over 9000"
End

Lbl M

Disp "Main program foo'!"     //This is where normal program execution starts

For(F,-1,0)                   //The tricky bit.  The first time the for loop loops, F=-1 and the if statement is true.  Goto A
If F                          //Once the sub is executed, it reaches an End which it THINKS is the same end that ends the For loop
Goto A                        //since the loop is still looping, control jumps [i]back into the for loop[/i]
End                           //F is now 0 and the condition is false.  Exit for loop :)

The code works by exploiting the fact that the TiOS cannot tell the difference between individual End's, and that jumping using Goto's does not clear Loop stacks.  Whenever the OS encounters an End, it will automatically assume that the End is paired with the most recent loop, and act accordingly.  
Title: Re: In-Program Sub-Routines
Post by: DJ Omnimaga on January 23, 2010, 01:36:00 am
I believe I saw another thread about this somewhere here but I totally forgot the name, thanks for posting this tho ^^
Title: Re: In-Program Sub-Routines
Post by: Builderboy on January 23, 2010, 01:44:55 am
I think it might have been in the long lost Portal 2 thread.  But yeah, this has been really usefull in the past :)
Title: Re: In-Program Sub-Routines
Post by: tifreak on January 23, 2010, 05:40:46 am
Another method I use for the same thing is using While loops. It can get really complex, so it is important to write it out on paper or on the computer so you can keep an eye on how many Whiles to Ends there are, but the idea is fast.

The idea is to have your master loop, and have the rest of your loops inside that. You don't even have to make them all Whiles, you can use If as well.

Quote from: BASIC Code
:ClrDraw
:1→W:0→F
:" →Str1
:0→Xmin:0→Ymin
:94→Xmax
:62→Ymax
:AxesOff
:GridOff
:While W=1
:25→A
:Text(‾1,0,10,"SPRITE-2-HEX
:Text(25,25,"NEW SPRITE
:Text(31,25,"EDIT SPRITE
:Text(37,25,"ABOUT
:Text(43,25,"QUIT
:2→W
:While W=2
:Text(A,20,">
:getKey→K
:If max(K={25,34:Text(A,20,"   
:A-6((K=25)(A>25)-(K=34)(A<43→A
:If max(K={21,105:Then
:If A=43:Then
:DelVar ADelVar WDelVar KClrDraw
:ClrHome
:Return:End
:If A=37:Then
:ClrDraw
:Text(‾1,0,10,"SRITE-2-HEX
:Text(13,0,"THIS PROGRAM CONVERTS
:Text(19,0,"8X8, 16X16, and 32X32
:Text(25,0,"SPRITES INTO HEXADECIMAL
:Text(31,0,"TO BE USED WITH THE
:Text(37,0,"HEX-2-SPRITE PROGRAM.
:Text(47,0,"SEND QUESTIONS TO:
:Text(53,0,"TIFREAK8XHOTMAIL.COM
:Pause
:ClrDraw
:1→W
:End
:If A=31:Then
:length(Str4
:Ans/(2+2(Ans>16)+4(Ans>64
:If min(Ans≠{8,16,32
:Then
:ClrDraw
:Text(0,0,"NO SPRITE IN MEMORY
:Pause
:ClrDraw
:1→W
:End
:If max(Ans={8,16,32:Then
:ClrDraw
:3→W:2→F
:End:End
:If A=25:Then
:ClrDraw
:Text(‾1,0,10,"SPRITE-2-HEX
:Text(15,1,"PLEASE SELECT SPRITE SIZE
:Text(30,25,"8X8
:Text(36,25,"16X16
:Text(42,25,"32X32
:Text(48,25,"BACK
:30→A
:4→W
:End:End
:While W=4
:Text(A,20,">
:getKey→K
:If max(K={25,34:Text(A,20,"   
:A-6((K=25)(A>30)-(K=34)(A<48→A
:If max(K={21,105:Then
:If A=48:Then
:ClrDraw
:1→W:End
:If A=30:8→Z
:If A=36:16→Z
:If A=42:32→Z
:If A<48:3→W
:End:End
:While W=3
:ClrDraw
:If Z=8:Then
:Line(40,31,40,38
:Line(41,30,48,30
:Line(49,31,49,38
:Line(41,39,48,39
:End
:If Z=16:Then
:Line(36,27,36,42
:Line(37,26,52,26
:Line(53,27,53,42
:Line(37,43,52,43
:End
:If Z=32:Then
:Line(28,19,28,50
:Line(29,18,60,18
:Line(61,19,61,50
:Line(29,51,60,51
:End
:Horizontal(7
:Text(56,0,"EXPORT                                                      QUIT
:If F=2:Then
:length(Str4
:Ans/(2+2(Ans>16)+4(Ans>64→Z
:If Z=8:Then
:41→I:24→J:End
:If Z=16:Then
:37→I:20→J:End
:If Z=32:Then
:29→I:12→J:End
:I→C:J→U
:For(B,1,length(Str4
:inString("123456789ABCDEF",sub(Str4,B,1
:If 7<Ans
:Pxl-On(U,C
:If 3<8fPart(Ans/8
:Pxl-On(U,C+1
:If 1<4fPart(Ans/4
:Pxl-On(U,C+2
:If fPart(Ans/2
:Pxl-On(U,C+3
:C+4→C
:U+(C=I+Z→U
:If C=I+Z:I→C:End
:End
:45→M:35→N:6→W
:StorePic Pic4
:End
:While W=6
:Pt-Change(M,N
:getKey→K
:If max(K={24,25,26,34
:Then
:Pt-Off(M,N
:RecallPic Pic4
:M-(((K=24)((Z=8)(M>41)+(Z=16)(M>37)+(Z=32)(M>29))-((K=26)((Z=8)(M<48)+(Z=16)(M<52)+(Z=32)(M<60→M
:N-(((K=34)((Z=8)(N>31)+(Z=16)(N>27)+(Z=32)(N>19))-((K=25)((Z=8)(N<38)+(Z=16)(N<42)+(Z=32)(N<50→N
:End
:If K=21
:Then
:RecallPic Pic4
:Pt-On(M,N
:StorePic Pic4
:End
:If K=31:Then
:RecallPic Pic4
:Pt-Off(M,N
:StorePic Pic4
:End
:If K=15:Then
:DelVar W
:ClrDraw:ClrHome
:End
:If K=11:Then
:Pt-Off(M,N
:RecallPic Pic4
:If Z=8:Then
:41→S:48→T
:24→Q:31→R
:End
:If Z=16:Then
:37→S:52→T
:20→Q:35→R
:End
:If Z=32:Then
:29→S:60→T
:12→Q:43→R
:End
:For(A,Q,R
:For(B,S,T,4
:8pxl-Test(A,B)+4pxl-Test(A,B+1)+2pxl-Test(A,B+2)+pxl-Test(A,B+3)→C
:Pxl-On(A,B
:If C=0:Str1+"0"→Str1
:If C>0
:Str1+sub("123456789ABCDEF",C,1)→Str1
:End:End
:sub(Str1,2,length(Str1)-1)→Str4
:DelVar Str1
:ClrDraw
:Text(0,0,"YOUR SPRITE HAS BEEN
:Text(6,0,"CONVERTED, PASTE Str4
:Text(12,0,"INTO A PROGRAM TO USE
:Pause
:0→W
:End:End:End:End
Generated by SourceCoder (http://www.cemetech.net/projects/basicelite/sourcecoder.php), © 2005 Cemetech (http://www.cemetech.net)

That is an example of the set up. I managed to get everything in one program without using a single Lbl or Goto. And if you close off each While correctly, you get no memory leaks. :p
Title: Re: In-Program Sub-Routines
Post by: JoeyBelgier on January 23, 2010, 06:31:25 am
Yeah well, I think I'm going with Builderboy's method, I can actually understand it :p
Title: Re: In-Program Sub-Routines
Post by: jsj795 on January 23, 2010, 01:32:47 pm
I usually use Repeat loop to do these things XD
Title: Re: In-Program Sub-Routines
Post by: Builderboy on January 23, 2010, 01:37:23 pm
Yeah, note that this method is really only used when you have a large chunk of code that needs to be used in many different places over the span of your program, and trying to reorganize your entire engine around that limiting factor would be either a hassle or downright impossible.  Obviously if you only ever call the routine once in your program it would be faster and easier to just recall the code to that spot :P
Title: Re: In-Program Sub-Routines
Post by: DJ Omnimaga on January 23, 2010, 03:10:49 pm
One issue to consider when using Goto is to never use them when the Lbl is completly at the bottom of a massive program. It takes a long while to load.
Title: Re: In-Program Sub-Routines
Post by: Builderboy on January 23, 2010, 04:37:57 pm
Right, thats why i suggest that you put the subroutines at the top, to preserve speed :)
Title: Re: In-Program Sub-Routines
Post by: miotatsu on January 23, 2010, 04:40:08 pm
ohhh this is much better than abusing recursion (eats up ram real fast that way) which is what piworld uses, i am definitely going to modify it to use this strategy instead
Title: Re: In-Program Sub-Routines
Post by: Builderboy on January 23, 2010, 04:41:29 pm
Yeah, i used recursion in one of my old games, and it ended up running really slow.  x.x
Title: Re: In-Program Sub-Routines
Post by: tifreak on January 23, 2010, 06:40:16 pm
I usually use Repeat loop to do these things XD

Problem with Repeat is that it always runs that loop at least once, before checking to see if it is true, while checks when it sees a while command. That is the difference.

And not trying to force this on anyone, just popping it out there that this works too :p
Title: Re: In-Program Sub-Routines
Post by: Builderboy on January 23, 2010, 06:44:19 pm
Well there are certain scenarios where Repeat is more usefull than while.  The simplest example that comes to mind is this

While 1

Repeat Ans
GetKey->K
End

...


End

Repeat is actually better than while in this situation because we DO want it to enter the loop, regardless of what ans was in the first place.  Using while, we would have to make sure that ans was not 0 before we enter.
Title: Re: In-Program Sub-Routines
Post by: miotatsu on January 23, 2010, 07:00:54 pm

Code: [Select]
Goto M                        //Start of Subroutine section.  We want it to be at the top of the program, as all subroutines are accessed via lables
                              //This code is skipped due to the Goto M statement
Lbl A                         //Subroutine A
Disp "This is a fun sub"
Disp "Its over 9000"
End

Lbl M

Disp "Main program foo'!"     //This is where normal program execution starts

For(F,-1,0                    //The tricky bit.  The first time the for loop loops, F=-1 and the if statement is true.  Goto A
If F                          //Once the sub is executed, it reaches an End which it THINKS is the same end that ends the For loop
Goto A                        //since the loop is still looping, control jumps [i]back into the for loop[/i]
End                           //F is now 0 and the condition is false.  Exit for loop :)

make sure the For( loop is closed tho because of the glitch with only one If statement, after the sub program is ran it returns to the For loop but the condition is false and if i remember correctly from the glitches thread a For( loop with a single If statement that is false can cause havoc, in that particular case it doesn't matter since you exit out after its done but if used in a big program it should be closed i would think :{o
Title: Re: In-Program Sub-Routines
Post by: DJ Omnimaga on January 23, 2010, 07:30:59 pm
The glitch will actually cause the entire game to run at like half the speed (or close) until you press ON in some cases. If that doesn't happen, there will still be a considerable slowdown during For loop, though
Title: Re: In-Program Sub-Routines
Post by: ztrumpet on January 23, 2010, 08:54:31 pm
Thank you for posting that.  I'm glad you are showing this, as it's very nice.
I think it might have been in the long lost Portal 2 thread.  But yeah, this has been really usefull in the past :)
I found it there a long time ago (before I was a member here) and started using it often.  If you look through the Escape code, you can find my first attempts of using this method.  I will be using it in the battle code for Elmgon.

Thanks for posting this!
Title: Re: In-Program Sub-Routines
Post by: Builderboy on January 24, 2010, 12:25:05 am
Mmmm yeah good catch.  I fixed it.  I actually never had the problem keep happening after the for loop had finished, but it is a strange error/glitch and definitely should be avoided.
Title: Re: In-Program Sub-Routines
Post by: Silver Shadow on January 24, 2010, 11:53:13 am
At least I won't need to create hundreds of subprograms!
DJ, you said that the glitch causes the calc to run at half speed, but are you talking about the method in the 1st post or just about memory leakage?
Title: Re: In-Program Sub-Routines
Post by: ztrumpet on January 24, 2010, 12:20:08 pm
At least I won't need to create hundreds of subprograms!
DJ, you said that the glitch causes the calc to run at half speed, but are you talking about the method in the 1st post or just about memory leakage?
He's talking about If s (No Then) in For( loops without closing brackets on the For loop.
http://tibasicdev.wikidot.com/for Check a little under optimization.
Title: Re: In-Program Sub-Routines
Post by: DJ Omnimaga on January 24, 2010, 02:51:19 pm
I wish XCOPY/Resource existed or that Flash Gordon was more reliable when I did Zelda, it would have maybe 45 subprograms at most instead of 200 x.x
Title: Re: In-Program Sub-Routines
Post by: TIfanx1999 on January 24, 2010, 05:34:53 pm
Your Zelda had about 200 subprograms? O_o
Title: Re: In-Program Sub-Routines
Post by: DJ Omnimaga on January 24, 2010, 05:46:31 pm
Around that or maybe 210. That was because I had so extreme limited RAM that I had to split every small routine into their own program even if they were repeated only twice in the entire game. Same fashion as the TI-81 Illusiat


Zelda DLQ was just created 6 months too early
Title: Re: In-Program Sub-Routines
Post by: Galandros on January 24, 2010, 05:57:15 pm
I wish XCOPY/Resource existed or that Flash Gordon was more reliable when I did Zelda, it would have maybe 45 subprograms at most instead of 200 x.x
How is it possible to follow the code? I couldn't handle that code without quitting for sure...
Title: Re: In-Program Sub-Routines
Post by: DJ Omnimaga on January 24, 2010, 05:59:56 pm
well each routines are pretty small. The problem is that there are so many that it can become hard to remember what they were.


Note that I was very lucky with Zelda DLQ. When I finished it I found no bug in it afterward, so no need to debug or anything.
Title: Re: In-Program Sub-Routines
Post by: cooliojazz on January 25, 2010, 12:14:36 am
Wait, you created a bug free program, ON THE FIRST TRY?!?!?!
Title: Re: In-Program Sub-Routines
Post by: DJ Omnimaga on January 25, 2010, 12:24:11 am
Yea, basically the beta tester team I hired prior release wouldn't even have to report anything. Not that anyone got able to play the game, though, thanks stupid TI for releasing a TI-Connect build supporting a different 8xg format