# Tips for golfing in SmileBASIC

SmileBASIC deserves more attention. I've only seen 3 users here (including myself!) providing SB answers, and while that doesn't surprise me, it disappoints me. It being a paid lang as well as being a BASIC dialect certainly turns people off, but for those who own it it's actually pretty flexible and, surprisingly, golfable. I figured I'd open this tips thread for it and see what comes up.

I expect 12Me21 to visit frequently :)

# Replace string!="" with string>""

SB allows you to do greater/less comparisons on strings, based on their codepoints. However, the empty string is considered the smallest string there is.

So for situations where you do string!="" you can use either string>"" or ""<string, since every string is greater than "" and "" is less than every string. Depending on whether you use < or > depends on if the statement needs whitespace before or after to be valid syntax, which can also save you bytes.

For example:

WHILE S$!=""  can be turned into WHILE S$>""


and further golfed to

WHILE""<S$ • All strings are truthy. Even empty ones. – snail_ Feb 7 '17 at 16:34 • Ah, okay. Makes sense. – Riker Feb 7 '17 at 16:36 # Using ?, ., @, and unclosed strings Many dialects of BASIC support ? for printing, and SB is no exception. Having an extremely short text output function is a big advantage. In SmileBASIC, . is evaluated to 0.0, so it can be used in place of 0 to save space. For example: SPSET 0,21 can be SPSET.,21, saving 1 byte. (SPSET0,21 is invalid because SPSET0 could be a user defined function) EXEC. is an extremely short way to make a program loop forever (but it resets all your variables, so it's not always usable) Labels (used for GOTO, GOSUB, and reading DATA) are represented as @LABEL in SmileBASIC. When used in an expression, they are actually treated as strings. For example, BGMPLAY"@305C" can be written as BGMPLAY@305C Strings are automatically closed at the end of a line (or the end of the program). ?"Hello, World!" can be written as ?"Hello, World!. This can also be used to make programs more readable by splitting them into multiple lines without changing the length: ?"Meow"BEEP 69 can be ?"Meow BEEP 69  • Wow, using labels to start MML is insane. Would've never thought of that, though it does limit your character set. – snail_ Feb 7 '17 at 16:46 • Another place I used it was to check if a hexadecimal digit was a number or a letter: @A<POP(H$) is shorter than "@"<POP(H$) (the A doesn't matter, it only ever checks the first character since it will never be the same) – 12Me21 Feb 7 '17 at 16:52 # Use string indexing instead of MID$

The MID$ function is a common function in many BASICs to get a substring from somewhere in the middle of a string. However, if you just need to get the character at some index, using string indexing is far shorter. For example: PRINT MID$("ABC",2,1)
PRINT "ABC"[2]


Both of these print C. Strings support array-like indexing on a character basis, so if you only need to check one character at a time, this is the best way to do it.

• You should talk about how strings can be modified this way. A$=@AA:A$[2]="BD":A$[0]="":A$[2]="C" – 12Me21 Feb 7 '17 at 17:03
• I'll probably write a set of answers about how strings are basically character arrays but even better, because putting it all into one is quite a task. – snail_ Feb 7 '17 at 17:05
• ...or you could write some ;) – snail_ Feb 7 '17 at 17:05
• I'm not very familiar with how it works in other languages. – 12Me21 Feb 7 '17 at 17:07

# When to use : (or not)

The : character is used as a statement-breaker in SB. Basically, you use it to stack statements on one line like so:

PRINT "HELLO!":PRINT "GOODBYE!"


Otherwise, your average statement is broken by a newline:

PRINT "HELLO!"
PRINT "GOODBYE!"


In reality, you often don't need to use the colon at all. So long as statements can be broken into syntactically valid tokens, the parser tends to figure out when one ends and the other starts. The same often goes for whitespace.

PRINT"HELLO!"PRINT"GOODBYE!"


Of course, this doesn't always work. There are always ambiguous cases and invalid syntaxes where you have to explicitly break statements. Take for example:

PRINT "HELLO";END


The semicolon means that PRINT is expecting another expression to print out, unless the statement breaks there (we use dangling semicolons to suppress the newline.) Here it assumes END is supposed to be a value, despite being a keyword, and tries to print it, resulting in an error. Thus, we have to explicitly break this statement, be it the colon or the newline.

In general, if something seems ambiguous, try it to see if it works. If it doesn't, break the statement. In addition, anything that would produce invalid syntax isn't highlighted correctly as 12Me21 mentioned.

# Use the syntax highlighter!

SmileBASIC's code editor has a built in syntax highlighter, that can be used to determine whether code will work or not. For example, if you try to do BEEP0, it will not highlight it, because there needs to be a space between a function and a digit. However BEEP. works, because . is not a digit.

Normally code like X=7BEEP is valid, since functions can't start with a number, so SB assumes that 7 and BEEP are separate. However. X=7END is NOT allowed (and not highlighted), because it tries to interpret 7E... as a number, but since there's no digit after the E, it fails, causing an error. Normally this would be pretty hard to figure out, but with a very reliable syntax highlighter, it's much easier to tell what you can and can't do.

My SmileBASIC syntax highlighter is designed to (hopefully) perfectly match the behavior of SB, so you can use it to check if code is valid.

<!DOCTYPE html>
<html>
<meta charset="utf-8">
<script src="https://12Me21.github.io/sbhighlight3/sbhighlight.js"></script>
<script>
function update(event){
$code.textContent=$input.innerText;
//must be innerText since contentedible and textContent are too dumb to understand linebreaks
//contenteditable adds <br>s which textContent ignores
//whyyyyy
applySyntaxHighlighting($code,true); } function setCaretPosition(elem,caretPos){ if(elem){ if(elem.createTextRange) { var range=elem.createTextRange(); range.move('character',caretPos); range.select(); }else{ if(elem.selectionStart){ elem.focus(); elem.setSelectionRange(caretPos,caretPos); }else elem.focus(); } } } </script> <style> #editcontainer{ position: absolute; } #editcontainer>pre{ position: absolute; left: 0; top: 0; } pre.csssucks *{ color:transparent !important; background-color:transparent !important; caret-color: white; } pre.csssucks { color:transparent !important; background-color:transparent !important; caret-color: white; border-color:transparent; padding-right: 50ch; } </style> </head> <body> Use SB font:<input type="checkbox" autocomplete="off" onchange="$code.dataset.sbfont=$input.dataset.sbfont=this.checked;update()"></input> <button onclick="update()">force update</button> <hr> <div id="editcontainer"> <pre id="$code">test</pre>
<pre id="\$input" class="csssucks" contenteditable="true" spellcheck="false" onkeydown="setTimeout(function(){update(event)},2);">test</pre>
</div>
</body>
</html>

# Avoid the MOD operator

The modulus operator is really long, and should be avoided if possible.

If you're getting characters from a string, you can just repeat the string instead:

"ABC"[X MOD 3]
("ABC"*9)[X] (assuming X will always be less than 27)


Sometimes you can save 1 character with AND instead:

X MOD 4
3AND X


# Omitting OUT return values

An OUT form function is one with multiple returns; you specify the variables to accept the return values after the OUT keyword. An example using DTREAD:

DTREAD OUT yearVar,monthVar,dayVar


But what if you only want one of the values, like the current month? You can "ignore" the rest of the values by simply not writing any variable name to accept them! You do, however, have to leave in the commas (aside from the occasional optional return.)

DTREAD OUT ,monthVar,


Which can be further golfed to

DTREAD OUT,M,