Tips for golfing in SmileBASIC

11

2

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 :)

snail_

Posted 2017-02-07T16:23:18.257

Reputation: 1 982

Answers

11

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$

snail_

Posted 2017-02-07T16:23:18.257

Reputation: 1 982

All strings are truthy. Even empty ones. – snail_ – 2017-02-07T16:34:22.517

Ah, okay. Makes sense. – Rɪᴋᴇʀ – 2017-02-07T16:36:26.897

6

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

12Me21

Posted 2017-02-07T16:23:18.257

Reputation: 6 110

Wow, using labels to start MML is insane. Would've never thought of that, though it does limit your character set. – snail_ – 2017-02-07T16:46:35.303

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 – 2017-02-07T16:52:29.107

3

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.

snail_

Posted 2017-02-07T16:23:18.257

Reputation: 1 982

You should talk about how strings can be modified this way. A$=@AA:A$[2]="BD":A$[0]="":A$[2]="C" – 12Me21 – 2017-02-07T17:03:26.007

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_ – 2017-02-07T17:05:15.960

...or you could write some ;) – snail_ – 2017-02-07T17:05:48.297

I'm not very familiar with how it works in other languages. – 12Me21 – 2017-02-07T17:07:56.810

2

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>
 <head>
  <meta charset="utf-8">
  <script src="https://12Me21.github.io/sbhighlight3/sbhighlight.js"></script>
  <link rel="stylesheet" type="text/css" href="https://12Me21.github.io/sbhighlight3/style.css">
  <link rel="stylesheet" type="text/css" href="https://12Me21.github.io/external/smilebasicfont.css">
  <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>

12Me21

Posted 2017-02-07T16:23:18.257

Reputation: 6 110

2

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.

snail_

Posted 2017-02-07T16:23:18.257

Reputation: 1 982

1

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

12Me21

Posted 2017-02-07T16:23:18.257

Reputation: 6 110

0

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,

snail_

Posted 2017-02-07T16:23:18.257

Reputation: 1 982

0

Use LAST()

Now that SmileBASIC 4 is out in Japan, we can check out some of the potential golf savings. One that immediately jumps out to me is the new LAST() function, which returns the last index of an array or string. You can save one byte.

LEN(v)-1 'old way
LAST(v)  'new way

snail_

Posted 2017-02-07T16:23:18.257

Reputation: 1 982