SmileBASIC golfing tips

** Constructing programs Don't write illegible code right away. Start by writing out your logic/program flow in language or diagrams, so you know what your program does before you don't anymore If you can't see far enough ahead to know how the logic works out already, you can still start by writing out your program as normal SmileBASIC code first. On your first draft, don't omit whitespace, keep variable names meaningful, and don't worry about optimizing numbers. You can prepare code structure so that it will be easier to optimize later, but this should be things like avoiding functions, not using long data strings, and adding comments, NOT "optimizing." You might continue to make changes to this draft, but get it to a point where it works the way you want it to, i.e. the "function" is complete. Be sure to check for any bugs at this stage too: it will be much harder to fix them later. Make a backup of this file to reference later (you might also want to write the golfed version in the same file to reference it, so having a copy is good). The next step is less destructive edits, such as moving instructions around (see notes on when spaces/instruction separators are actually necessary), changing loop types, and trying to find better approaches to your logic. Then, optimize out redundancy and comments (you should know your code pretty well, and there's always the clean copy). Start removing whitespace, and especially play with newlines/instruction separation/instruction parsing. If you have hardcoded data, try to reduce it (see data section) or even remove the need for it. Know how long your variables are so you can exclude them from the total score. The last step, once all logic has been golfed, is to remove formatting and replace variable/label/function names with one-letter mnemonics. You should be able to estimate your final score before this step, so don't do it prematurely just to measure code size. Also, write down the reduced symbols and their meaning somewhere, whether in a sticky note or as remarks in the clean file. Also, I've noticed that some people disable the syntax highlighting or make it useless colors. This is a mistake here. The highlighter is your friend as to what is valid in OSP. ** Easy Stuff *** ? vs. PRINT ~?~ is shorthand for PRINT On the subject of printing, you can usually use a comma or semicolon to separate numeric arguments, rather than converting with STR$ *cost:* 1 *use when:* always *** function aliasing and redundancy optimization Almost all operations that need no arguments (e.g. operate on globals) can be converted to a function or alias if they are used more than 2 or so times #+BEGIN_SRC smilebasic DEF X END #+END_SRC *cost:* 10 + calls (-1 if last character in body is non-alphanumeric) *use when:* len(body) * calls - calls > 10 *example:* #+BEGIN_SRC smilebasic 'before B=POP(STACK):FOO(B+1):B=POP(STACK):FOO(B+1):B=POP(STACK) 'after DEF P B=POP(STACK)END:P:FOO(B+1)P:FOO(B+1):P E+END_SRC *** words and whitespace The definition for a word is [A-Z][A-Z0-9]* (case insensitive). Instructions are words. This means that unless the next character is a letter or a number, you don't need whitespace following a statement. *cost:* - *use when:* statements can be rearranged such that a non-alphanumeric follows another word *example:* #+BEGIN_SRC smilebasic 'before GOTO @L 'after [email protected] #+END_SRC *** numbers and whitespace similarly, since a digit can't be the first character in a word, and numbers with letters in them are invalid, whitespace/command separators following numeric literals are usually unnecessary ~I=I+1FOO()~, for example, is perfectly valid and read as ~I=I+1:FOO()~. There is an exception however: decimal numbers allow scientific notation with an upper or lowercase E immediately following the first numeric part. This means that ~12END~ is illegal (since "ND" is not a valid exponent) *cost:* - *use when:* number is not followed by a word beginning with E *** omitting end quotes The end of a line also ends strings. In OSP this isn't useful, but if you can end a string before the line wrap, it might save a single character *cost:* -1 *use when:* strings are perfectly aligned with the wrap point. ** data Literal data should be avoided whenever possible. Nothing kills your character count faster than the epic poem you wrote for an intro crawl. While [[][generative content]] may be an option in some cases, there are some tricks that can help cut down the cost of using data. *** don't use separate DATA statements #+BEGIN_SRC DATA"A" DATA"B" 'is the same as DATA"A","B" #+END_SRC *cost:* 1 (,) *use when:* always, net saving is 3 * lines *** use string variables instead of DATA it's best to avoid DATA, but the biggest reason is because of the code needed to read it in. At best it's something like #+BEGIN_SRC smilebasic DIM A[9]COPY A,"@L" #+END_SRC and forget about a iterating loop. Instead, it's usually possible to assign a string to variable and then access that. This works for numeric data using ASC() and with strings with a little more cleverness in formatting. *note that all source characters must be readable (non-[X]). This means full source compression is usually not a viable option*