8
\$\begingroup\$

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

Please post one tip per answer.

\$\endgroup\$
3

4 Answers 4

5
\$\begingroup\$

Unary output without loops

The official interpreter implements the Write command using exec("print(chr(%s), end='')" % expr), opening a window for code injection exploits. Despite this, the potential for such exploits remains limited because expr can only include the characters 0-9a-z_N()*/%^+-, and it prohibits consecutive alphabets or underscores.

An example of a code injection exploit involves using an expr formatted as a)*(b. This format leads to the execution of print(chr(a)*(b), end=''), enabling the character with the ASCII code a to be printed b times without the need for a loop.

Example

# Output the character '/' 10 times:
Write 47)*(10

# Note that both 'a' and 'b' in the form 'a)*(b' can be complex expressions:
2890
Write _/64)*(_%64

Try it online!

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

Omit Braces When Possible

Unlike some golfing languages, Acc!! does not automatically close braces. However, a known bug in the official interpreter occasionally allows for the omission of braces.

Due to specific implementation details, the } character serves a dual purpose in the official interpreter: it terminates the loop and increments the associated loop variable. Therefore, you can only safely omit the closing } if your code does not depend on the loop variable being incremented on each iteration.

Example

Count i while _-90 {
  _*2
  Count j while _%50-40 {
    _+10
    Write 10
    Count k while _-k {
      Write 48
    }  # This cannot be omitted because the loop depends on k being incremented.
  }  # This can be omitted since the code does not rely on j.
}  # This can also be omitted as the code does not depend on i.

Try it online!

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

Use bitmasks to distinguish small values

When checking whether an expression is equal to one of several small integer values (mostly useful with ASCII codes) it's often shorter to use a bitmask. For example, if checking if an expression is equal to 3 or 5, there are two potential ways:

  • 0^(x-3)^2+0^(x-5)^2 - 17 bytes + 2 * x's length
  • 40/2^x%2 - 7 bytes + x's length (potentially +2 for parens)

This works as 40 in binary is equal to 101000 - 1 bits in the 3rd/5th positions and 0s elsewhere. 40/2^x%2 gets the xth bit of 40, so it returns 1 if x is 3 or 5 and 0 otherwise.

Some usecases of this:

  • 3302829851648 (used here) returns 1 for 10, 32, 40, and 41 - newline, space and parentheses.
  • 1023*2^48 (from the same answer) returns 1 when given the ASCII code of a digit and 0 otherwise.
  • 5*2^91 (from this golf to this answer) returns 1 when given [ or ] and 0 otherwise (among others)

Depending on the usecase, this can save anywhere between 2 and 60+ bytes.

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

Conditional character output

(an extension of this tip that deserves its own answer)

From the linked tip, you can do something like Write 47)*(10 to print / (chr(47)) 10 times. But replacing that 10 with 0 will print nothing, so you can replace

Count j while [cond]-j {
Write [expr]
}

with

Write [expr])*([cond]

saving 18+ bytes.

(I saved about 120 bytes on my tinylisp interpreter with this)

Side note: If your cond is of the form 0^(x) or 0^0^(x), where the parentheses are required, you can do [expr])*0^([cond] or similar to save two bytes.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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