14
\$\begingroup\$

What general tips do you have for golfing in Whitespace? I'm looking for ideas which can be applied to code-golf problems and which are also at least somewhat specific to Whitespace (e.g. "remove comments" is not an answer).

Please post one tip per answer.

\$\endgroup\$
  • 79
    \$\begingroup\$ Remove unnecessary whitespace. \$\endgroup\$ – KSFT Apr 5 '15 at 0:57
  • 1
    \$\begingroup\$ s/[^[:space:]]//g \$\endgroup\$ – Digital Trauma Apr 5 '15 at 1:13
10
\$\begingroup\$

I'm not entirely sure whether this is a joke question or not, so I hope I don't get mocked for taking it seriously, but...

Tip 1: Don't End Your Program

The spec says that a program should be ended by three line-feeds, [LF][LF][LF], where the first is the flow control IMP, and the next two are the quit command, but many interpreters will just run your code without the proper ending. Saves you 3 characters in any program.

\$\endgroup\$
5
\$\begingroup\$

Tip 2: Use The Heap As Little As Possible

I used to use the Heap a lot for counting my loops and such, but realised it was actually extremely inefficient; first pushing an address, getting the current count, taking/adding one, re-pushing address, etc.

Now I just push a value on the stack to act as loop counter, then use the [Space][LF][Tab] swap command to get back to it when I need it. It takes a lot of working in/around, but when you get it it can really reduce your char count.

\$\endgroup\$
4
\$\begingroup\$

Use arbitrary heap addresses

Many interpreters allow you to read/write to arbitrary heap addresses instead of starting at 0 or 1 and counting up. You can duplicate an existing stack value (3 bytes) to use as an address instead of pushing a new value (minimum 4 bytes)

\$\endgroup\$
  • \$\begingroup\$ +1. Note that this only applies to non-negative heap-addresses. So if the top of the stack is a negative integer, you can't use it as heap-address. \$\endgroup\$ – Kevin Cruijssen Mar 13 '18 at 10:47
4
\$\begingroup\$

The empty sequence is a valid label

[LF][Space][Space][LF] (Flow Control - Mark with the label '') creates an empty label that is a valid target for jumps or subroutine calls. This saves a byte when declaring the label and a byte every time it is called.

(Observed in the whitespace answer for implement a truth machine)

\$\endgroup\$
4
\$\begingroup\$

Lower all characters by a fixed amount and add that right before printing in a loop

Credit to @LukStorms, who uses a similar approach in his answer for the Hello World challenge.

(STN used for Space, Tab, and New-line respectively.)

Pushing the values for letters is always 11 bytes (i.e. pushing the value 65 for the character 'A' is SSSTSSSSSTN; pushing the value 122 for the character 'z' is SSSTTTTSTSN). When you want to output large amount of text this can be expensive. Instead, you can lower the values of all the characters you want to print by a fixed amount, and then in the loop to print them add this fixed amount.

This can be done with the following code (let's assume the fixed value is 100 in this case):

  1. Push all values for the characters (minus the fixed amount 100) in reverse order
  2. NSSN (Create a Label_0; basically starting the loop)
    1. SSSTTSSTSSN (Push the fixed amount 100)
    2. TSSS (Add the top two values of the stack together)
    3. TNSS (Pop and print the now correct value as character)
    4. NSNN (Jump to Label_0; go to the next iteration of the loop)

This will stop the program with an error (which is allowed according to the meta) as soon as it tries to do the Add (TSSS) with nothing more on the stack. I've used this to golf this answer of mine (see items 5 and 6 of Things I did to lower the byte-count).

Whether a fixed amount of 100 is the shortest approach depends on what you are printing. @LukStorm for example used 107 in his Hello World answer.

Note that copying the top value (SNS) for two of the same adjacent characters (like the l in Hello), or copying values from another position can still be used in addition to this to golf more bytes.

\$\endgroup\$
3
\$\begingroup\$

Jumping to undefined labels ends the program (in some interpreters)

This starts to get into implementation specific behaviour, but I believe this is allowed.

TIO (and possibly other interpreters? doesn't work on ideone at least) will stop execution when an attempt is made to jump to a label that doesn't exist. If you need to do a comparison to break out of a loop this allows you to save bytes by not declaring the break label. (See my comment on Print Invisible Text for an example.)

\$\endgroup\$
3
\$\begingroup\$

The value 0 can be declared as a number with no binary digits

The whitespace tutorial mentions that numbers can be any number of bits/binary digits wide. This means a number with no bits (beyond the required sign bit) is a valid representation of the value 0. [Space][Space][Space][LF] and [Space][Space][Space][Space][LF] both push the value 0 to the stack but the former is one byte shorter.

\$\endgroup\$
0
\$\begingroup\$

Copying previous integers can be shorter than creating new ones

(STN used for Space, Tab, and New-line respectively.)

STS + Number argument can be used to Copy the nth item on the stack (given by the argument) onto the top of the stack. This can in some cases be used to save bytes.

For example, in this answer of mine I explained in the 4th item of Things I did to lower the byte-count how copying the 1st (0-indexed) value (STSSTN) is shorter than pushing 12 to create the character 'p' (SSSTTSSN) in the part "pop" of the output. (NOTE: I use the value 12 instead of 112 for the character 'p', because I've applied this other tip of lowering all values by a fixed amount, which we add before printing the characters in the loop.)

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.