kl99 Posted August 14, 2019 Share Posted August 14, 2019 Hi, Programming within only 10 lines of code requires a different coding style. Let us take this thread to share the findings and ideas everyone had to tweak in some more bytes. Here is my first: Variable Name Length Use single char variable names. BASIC allows A,B,C,D,E,F,G,...X,Y,Z,@,[,],_ as Names for the first character, which in most cases should be enough. Same for String Variables or Arrays. Skip Variable Initialize to 0 You can skip initializing a variable to 0 before its first reference as this is done by the system. Replace repeating numbers in code You save length in your code lines if you replace a number (BASIC calls them numeric constant) that is showing up multiple times across your program by a reference to a variable having that numeric value. The more occurences you can replace the more you save. The more digits the number had the more you save. A nice combination of this tip with the tip skipping initialize to 0 would be replacing each occurence of the number 0 in your program with "_" and simply never initialize or change its value. 2 Quote Link to comment Share on other sites More sharing options...
+OLD CS1 Posted August 16, 2019 Share Posted August 16, 2019 On 8/14/2019 at 3:47 AM, kl99 said: A nice combination of this tip with the tip skipping initialize to 0 would be replacing each occurence of the number 0 in your program with "_" and simply never initialize or change its value. What benefit does this provide? Quote Link to comment Share on other sites More sharing options...
kl99 Posted August 16, 2019 Author Share Posted August 16, 2019 Let's take Gladiator by FarmerPotato, written in XB and extend each line with ! characters to see how many more "bytes" would fit in each line. 10 CALL CLEAR :: CALL SCREEN(8):: CALL MAGNIFY(2):: S=2 :: T=1 :: R=80 :: C=128 :: Q=160 :: E=2 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 20 CALL CHAR(113,"003030300000000000000030303000000000000000303030",116,"2556360A060A090F661F66060A0A00090606076E1665")!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 30 CALL CHAR(97,"606848706070506860604078606050D86060406070686070",100,"1819121C101814641818101E1030484C30302030303E186C")!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 40 CALL CHAR(105,"102040000000000000000000007000000000000000000070",108,"020408000000000000000000000E0000000000000000000E")!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 50 CALL SPRITE(#1,104+S,12,R-4,C+6,#2,112+T,7,R-1,C-1,#3,96+S,2,R,C,#4,115+E,16,R,Q)!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 60 L=K :: CALL JOYST(1,X,Y):: CALL KEY(1,K,Z):: Y=2-Y/4 :: IF K=18 THEN S=Y ELSE IF L=18 THEN F=4 :: S=Y+3 ELSE T=Y :: IF X THEN C=C+X ELSE IF S>3 THEN S=S-3 :: F=0 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 70 E=INT(RND*3+1):: Q=Q-1 :: CALL PATTERN(#1,104+S,#2,112+T,#3,96+S,#4,115+E):: CALL LOCATE(#1,R-4,C+6,#2,R-1,C-1,#3,R,C,#4,R,Q)!!!!!!!!!! 80 IF C+8+F<Q THEN 60 ELSE IF F AND S<>E+3 THEN 100 ELSE IF T=E OR S-3=E THEN C=C-8 :: Q=Q+8 :: GOTO 70 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 90 CALL COLOR(#4,9):: FOR I=1 TO 7 :: CALL SOUND(-100,999,2):: CALL SOUND(-100,880,2):: NEXT I :: C=C-8 :: Q=Q+16 :: GOTO 50 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 100 CALL COLOR(#3,9):: FOR I=1 TO 7 :: CALL SOUND(-100,999-I*100,2):: NEXT I :: C=C-16 :: Q=Q+8 :: GOTO 50 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! You can fit 502 ! characters in those 10 untouched lines. Now let's introduce 5 numeric variables as Numeric Constants for M=1,N=2,O=3,P=4,_=0 10 CALL CLEAR :: M=1 :: N=2 :: O=3 :: P=4 :: CALL SCREEN(8):: CALL MAGNIFY(N):: S=N :: T=M :: R=80 :: C=128 :: Q=160 :: E=N !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 20 CALL CHAR(113,"003030300000000000000030303000000000000000303030",116,"2556360A060A090F661F66060A0A00090606076E1665")!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 30 CALL CHAR(97,"606848706070506860604078606050D86060406070686070",100,"1819121C101814641818101E1030484C30302030303E186C")!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 40 CALL CHAR(105,"102040000000000000000000007000000000000000000070",108,"020408000000000000000000000E0000000000000000000E")!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 50 CALL SPRITE(#M,104+S,12,R-P,C+6,#N,112+T,7,R-M,C-M,#O,96+S,N,R,C,#P,115+E,16,R,Q)!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 60 L=K :: CALL JOYST(M,X,Y):: CALL KEY(M,K,Z):: Y=N-Y/P :: IF K=18 THEN S=Y ELSE IF L=18 THEN F=P :: S=Y+O ELSE T=Y :: IF X THEN C=C+X ELSE IF S>O THEN S=S-O :: F=_ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 70 E=INT(RND*O+M):: Q=Q-M :: CALL PATTERN(#M,104+S,#N,112+T,#O,96+S,#P,115+E):: CALL LOCATE(#M,R-P,C+6,#N,R-M,C-M,#O,R,C,#P,R,Q)!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 80 IF C+8+F<Q THEN 60 ELSE IF F AND S<>E+O THEN 100 ELSE IF T=E OR S-O=E THEN C=C-8 :: Q=Q+8 :: GOTO 70 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 90 CALL COLOR(#P,9):: FOR I=M TO 7 :: CALL SOUND(-100,999,N):: CALL SOUND(-100,880,N):: NEXT I :: C=C-8 :: Q=Q+16 :: GOTO 50 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 100 CALL COLOR(#O,9):: FOR I=M TO 7 :: CALL SOUND(-100,999-I*100,N):: NEXT I :: C=C-16 :: Q=Q+8 :: GOTO 50 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Suddenly you can fit 566 ! characters in those lines, meaning across 10 lines we saved 64 bytes. The definition of the constants in Line 10 did cost use some bytes but as soon as we start to reference those variables instead of using the actual number, we save bytes. This was only basic replacement of each reference of the number 0, 1, 2, 3, 4 and saved us already a lot. Now let's tweak a bit more... 50 CALL SPRITE(#M,104+S,P*O,R-P,C+6,#N,112+T,7,R-M,C-M,#O,96+S,N,R,C,#P,115+E,P*P,R,Q)!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Instead of "12" we use P*O and instead of "16" we use P*P and voila we save 2 more bytes alone in that line. Line 10 can be tweaked for 2 additional bytes by not defining Q=160 but with R+R: 10 CALL CLEAR :: M=1 :: N=2 :: O=3 :: P=4 :: CALL SCREEN(8):: CALL MAGNIFY(N):: S=N :: T=M :: R=80 :: C=128 :: Q=R+R :: E=N !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! If we define a constant for the number 100 in Line 90 and use it twice in the same line, then we need for the definition plus 2 references as much bytes as the untouched line. And each further occurence of a 3 digit number saves us 4 bytes. 90 H=100 :: CALL COLOR(#P,9):: FOR I=M TO 7 :: CALL SOUND(-H,999,N):: CALL SOUND(-H,880,N):: NEXT I :: C=C-8 :: Q=Q+P*P :: GOTO 50 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 100 CALL COLOR(#O,9):: FOR I=M TO 7 :: CALL SOUND(-H,999-I*H,N):: NEXT I :: C=C-P*P :: Q=Q+8 :: GOTO 50 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! let's check the program in completeness after such kind of tweaks... 10 CALL CLEAR :: M=1 :: N=2 :: O=3 :: P=4 :: D=8 :: H=100 :: J=112 :: CALL SCREEN(D):: CALL MAGNIFY(N):: S=N :: T=M :: R=80 :: C=P*P*D :: Q=R+R :: E=N !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 20 CALL CHAR(J+M,"003030300000000000000030303000000000000000303030",J+O,"2556360A060A090F661F66060A0A00090606076E1665")!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 30 CALL CHAR(H-O,"606848706070506860604078606050D86060406070686070",H,"1819121C101814641818101E1030484C30302030303E186C")!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 40 CALL CHAR(105,"102040000000000000000000007000000000000000000070",J-P,"020408000000000000000000000E0000000000000000000E")!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 50 CALL SPRITE(#M,H+P+S,P*O,R-P,C+6,#N,J+T,7,R-M,C-M,#O,H-P+S,N,R,C,#P,J+O+E,P*P,R,Q)!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 60 L=K :: CALL JOYST(M,X,Y):: CALL KEY(M,K,Z):: Y=N-Y/P :: IF K=18 THEN S=Y ELSE IF L=18 THEN F=P :: S=Y+O ELSE T=Y :: IF X THEN C=C+X ELSE IF S>O THEN S=S-O :: F=_ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 70 E=INT(RND*O+M):: Q=Q-M :: CALL PATTERN(#M,H+P+S,#N,J+T,#O,H-P+S,#P,J+O+E):: CALL LOCATE(#M,R-P,C+6,#N,R-M,C-M,#O,R,C,#P,R,Q)!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 80 IF C+D+F<Q THEN 60 ELSE IF F AND S<>E+O THEN 100 ELSE IF T=E OR S-O=E THEN C=C-D :: Q=Q+D :: GOTO 70 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 90 CALL COLOR(#P,9):: FOR I=M TO 7 :: CALL SOUND(-H,999,N):: CALL SOUND(-H,880,N):: NEXT I :: C=C-D :: Q=Q+P*P :: GOTO 50 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 100 CALL COLOR(#O,9):: FOR I=M TO 7 :: CALL SOUND(-H,999-I*H,N):: NEXT I :: C=C-P*P :: Q=Q+D :: GOTO 50 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! now we have 607 ! characters, meaning we saved over 100 bytes across the 10 lines. 4 Quote Link to comment Share on other sites More sharing options...
kl99 Posted August 17, 2019 Author Share Posted August 17, 2019 Initialize Variables to identical value together 100 A,B=1 110 PRINT A 120 PRINT B Instead of A=1 :: B=1 you can use A,B=1. How many bytes in your line takes a number? Does every number use the same number of bytes? First of all, how many digits your number has is important. The number 10 uses one more byte than 0-9. A negative number also takes one more byte for storing the negative character. Therefore really bad are numbers typically used with CALL LOAD and CALL PEEK, where you have to pass a >83xx hex number. The internal timer that sits on >8379 has to be called with "-31879", which uses 5 more byte than the number 4. If the precise value doesn't count, it makes sense to reduce numbers like 100 for defining the length of a sound to 99 or to a constant (tip above) that is close to that number. For the same reason it also makes sense to prefer to use Ascii Chars 32-99 instead of 100-159 to save a byte on each reference. A special case are line numbers. I didn't see a change to the length for defining the code for the line if the line number was defined by 1 digit or 5. Even if you have references to lines like you have in GOTO x or GOSUB x or THEN x ELSE x. If somebody studied this in more detail, please share with us. Quote Link to comment Share on other sites More sharing options...
kl99 Posted August 17, 2019 Author Share Posted August 17, 2019 To use or to not use DATA statements There are several ways to use DATA statements. You can go set pointers with RESTORE x to re-read some data once again, or before other data. If you need or utilitize the RESTORE then of course there is no need to discuss whether to use DATA statements or not. But if you only use it to initialize your numeric variables and string variables once, in the order they appear, then it is time to check the gain from them over a plain initialize of the same variables in a X=1 :: Y=9 :: ... way. DATA Statements First let's try to find out how much an entry in a DATA statement takes. 1 DATA 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 We can fit up to 39 single digit numbers in one DATA statements. Trying to fit a 40th number would result in a too long line. But we can increase one number by two digits and that is really the maximum that fits. 1 DATA 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,100 Every increase by a digit uses an extra byte, every negation of a number is an extra byte. We can therefore define DATA statements like below to figure out the actual usage of a single entry: 1x 155 (1 time a 155 digit number) 1x 151, 1x 1 (1 time a 151 digit number, 1 time a 1 digit number) 1x 147, 2x 1 1x 143, 3x 1 1x 139, 4x 1 1x 135, 5x 1 1x 131, 6x 1 1x 127, 7x 1 1x 123, 8x 1 ... 1x 11, 36x 1 1x 7, 37x 1 1x 3, 38x 1 (1 time a 3 digit number, 38 times a 1 digit number) This leads to the assumption that each entry takes 3 bytes plus 1 byte per digit, so at least 4 bytes. Tests revealed that strings are treated the same. Each entry takes 3 bytes plus 1 byte per character. Quotes are not counted. In addition to the DATA statement we need a READ statement that takes 2 additional bytes for reading one additional numeric variable. And it needs 3 additional bytes for reading one additional string variable. Summary: Numeric Variable: 6 bytes or more String Variable: 7 bytes or more Direct Variable definition Now we compare those findings to the costs of a direct variable definition. 3 A=1 :: B=1 :: C=1 :: D=1 :: E=1 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! space for 129 ! characters 3 A=1 :: B=1 :: C=1 :: D=1 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! space for 135 ! characters From this we can calculate that one definition plus seperator costs at least 6 bytes. Each additional digit is an extra byte, negation is an extra byte, an increase on the length of the variable name is an extry byte per character. Let's switch to String Variables: 3 A$="A" :: B$="A" :: C$="A" :: D$="A" :: E$="A" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! space for 124 ! characters. 3 A$="A" :: B$="A" :: C$="A" :: D$="A" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! space for 131 ! characters. From this we now know that each definition plus seperator costs at least 7 bytes. This is different from numeric variables because of the required $ character in the variable name. Summary: Numeric variable: 6 bytes or more String variable: 7 bytes or more My Conclusio From a line length in best case DATA statements cost the same amount of bytes as direct variable initialization. However you can not use a line with a DATA statement for anything else. So you will need to ensure that you use the whole program line to not loose bytes compared to direct variable definition. Also excluded from the comparison was the cost of the bytes required for the necessary READ command or even commands, only the additional bytes per variable for a read were taken into account. With direct variable definition you have the advantage of placing it wherever space is left or at the spot in the program where you need it. Speed was not taken into consideration. Also not taken into consideration were special ways of reading in the DATA values into Array Variables (100 FOR I=1 TO 16 :: READ C(I):: NEXT I). This could give you the edge again over direct variable definition. Quote Link to comment Share on other sites More sharing options...
kl99 Posted August 17, 2019 Author Share Posted August 17, 2019 How to enter special characters (non-printable) Ascii characters >= 127 I was also experimenting with using characters above 126 in string variables to store data in those. These are my findings how to achieve entering a certain Ascii Character. There is no way to enter Ascii Values 160-175 in immediate/edit mode. Same is true for Ascii Values 0-31 afaik. Some key combinations require the so called REM trick depending on the used Basic. RXB has some limitations as it allows some additionals keyboard shortcuts to move to the end of the line or beginning. The REM trick goes back to Stephen Shaw and the 80's. The Editor somehow behaves different once it detected there is a REM line being entered. FCTN+V 127 CTRL+, 128 CTRL+A 129 CTRL+B 130 CTRL+C 131 CTRL+D 132* might require REM trick CTRL+E 133* might require REM trick CTRL+F 134 CTRL+G 135 CTRL+H 136 CTRL+I 137 CTRL+J 138 CTRL+K 139 CTRL+L 140 CTRL+M 141 CTRL+N 142 CTRL+O 143 CTRL+P 144 CTRL+Q 145 CTRL+R 146 CTRL+S 147* might require REM trick CTRL+T 148 CTRL+U 149 CTRL+V 150 CTRL+W 151 CTRL+X 152* might require REM trick CTRL+Y 153 CTRL+Z 154 CTRL+. 155 CTRL+; 156 CTRL+= 157 CTRL+8 158 CTRL+9 159 --- CTRL+0 176 CTRL+1 177 CTRL+2 178 CTRL+3 179 CTRL+4 180 CTRL+5 181 CTRL+6 182 CTRL+7 183 FCTN+, 184 FCTN+. 185 FCTN+/ 186 CTRL+/ 187 FCTN+0 188 FCTN+; 189 FCTN+B 190 FCTN+H 191 FCTN+J 192 FCTN+K 193 FCTN+L 194 FCTN+M 195 FCTN+N 196 FCTN+Q 197 FCTN+Y 198 Quote Link to comment Share on other sites More sharing options...
+OLD CS1 Posted August 19, 2019 Share Posted August 19, 2019 A quick investigation with Classic99 debug: A=0 In its entirety (excluding line length and null line terminator bytes,) this statement is >41,>BE,>C8,>01,>30. The number part alone takes three bytes: >C8 (numeric literal indicator?) >01 (number length) and >30 (ASCII representation of the number zero.) Whereas B=A The entire statement (excluding line length and null line terminator bytes) takes up just three bytes: >42 (ASCII "B") >B2 (tokenized "=") >41 (ASCII "A") Thus each positive numeric literal takes up two bytes plus the ASCII representation of its value -- negative values are prefixed by >C2,>C8 giving one additional byte. This is also exactly how it appears in the VDP RAM crunch buffer at >0820. Interesting wizardry afoot. I remember reading in a Commodore 64 BASIC guide a long time ago that using a period in place of a 0 (zero) uses less memory and processes more quickly. TI XB will accept this for entry, but the value still consumes three bytes (>C8,>01,>2E) and, while it passes pre-scan, execution halts with * SYNTAX ERROR Quote Link to comment Share on other sites More sharing options...
kl99 Posted August 19, 2019 Author Share Posted August 19, 2019 3 hours ago, OLD CS1 said: A=0 In its entirety (excluding line length and null line terminator bytes,) this statement is >41,>BE,>C8,>01,>30. The number part alone takes three bytes: >C8 (numeric literal indicator?) >01 (number length) and >30 (ASCII representation of the number zero.) >C8 means unquoted string. >C7 would mean quoted string. Thanks for the analysis. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.