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.
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.
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.
# 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
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.
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.
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 length40/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 x
th 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.
(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.