# Auto-golf an esolang

The lack of a social life drove a poor nerd into inventing another superfluous esolang called !+~%. For no good reason it initializes the accumulator with 6 and knows the following commands:

• ! (out(Accu); Accu = 6) prints the accumulator value as decimal string to stdout (without newline) and resets the accumulator to its initial value 6
• + (Accu = Accu + 7) adds 7 to the accumulator
• ~ (Accu = uccA) reverses the order of digits of the decimal value in the accumulator
• % (Accu = 1Accu mod Accu) replaces the accumulator by (1 in front of the accumulator) modulo accumulator

Easier to understand with an example. %!+~! produces 431: Initially, the accumulator is 6. % replaces it by 16 mod 6, which is 4, which is printed by the following !, while the accumulator is reset to 6. + adds 7 and the ~ command reorders the 13 to be 31, which is printed

For some boring-to-proof reason, the language allows to print any non-negative integer and code golfers around the world are seriously concerned about a flood of »what is the shortest code to produce 6431?« type of challenges. But you can prevent that!

Task: Write a program to output the code golfed !+~% code to produce a given number!

Input: A non-negative integer value in any format yo love (except !+~% ;-)

Output: The shortest !+~% code to produce that output (only one of the possible solutions)

The shortest code (in any language) wins.

Test data:

0     --> ++%!
1     --> +%%!
2     --> %%!
3     --> +~%%!
4     --> %!
5     --> +++%%!
6     --> !
12    --> +++%%+!
20    --> ++!
43    --> ++++~!
51    --> +%%++~!
654   --> !+~++~!
805   --> +++%~++~+~!
938   --> +%!+~+!
2518  --> %+++!%++!
64631 --> !%!!+~!

• To prove that the language allows to print any non-negative integer, give code that generate 0-9 is enough, [wc]ould u add them? :)
– l4m2
Commented Dec 11, 2023 at 9:13
• Got they 7 +~%! 8 %+%+! 9 +%!
– l4m2
Commented Dec 11, 2023 at 9:14
• see you require uniqueness
– l4m2
Commented Dec 11, 2023 at 9:15
• @l4m2 Actually having the numbers up to 6 is enough for the boring proof,, because you can construct everything else by adding 7. Commented Dec 11, 2023 at 9:45
• Fun fact: the name of !+~% is the program which outputs 6, then sets the accumulator to 7. Commented Jan 14 at 19:59

# JavaScript (ES6), 139 bytes

-1 thanks to @l4m2

Expects the target integer as a string.

n=>eval("for(k=0;(g=i=>i?g(i>>2,v=(i&=3)<3?[v+7,+[...v+''].reverse().join,('1'+v)%v][i]:(r+=v,6),o+='+~%!'[i]):r)(k++,o=r='')!=n;v=6);o")


Try it online!

• 139
– l4m2
Commented Dec 11, 2023 at 9:22

# 05AB1E, 47 bytes

"%!+~"∞5в0δKÙ.Δ´6svyiˆ6ëÐÂr1ìs%s7+)yè}}ˆ¯JQ}1ªè


Brute-force, so pretty slow. Outputs as a list of characters.

Explanation:

"%!+~"          # Push this string (which we use at the end)
∞              # Push an infinite positive list: [1,2,3,...]
5в            # Convert each integer to a base-5 list
δ          # Map over each inner list:
0 K         #  Remove all 0s
Ù        # Uniquify this infinite list of lists
.Δ             # Pop and find the first list that's truthy for:
´            #  Empty the global array
s            #  Swap so the current list is at the top of the stack
v           #  Pop and loop over its digits:
yi         #   If the current digit is a 1:
ˆ        #    Pop and add the current integer to the global array
6        #    Push a 6 to reset
ë         #   Else (the current digit is a 2, 3, or 4):
Ð        #    Triplicate the current integer
Â       #    Bifurcate the top; short for Duplicate & Reverse copy
r      #    Reverse the order of the (four items on the) stack
1ì      #    Prepend a 1
s     #    Swap the top two values
%    #    Modulo
s       #    Swap the top two values again
)   #    Wrap all three items into a list: [reverse(n),1n%n,n+7]
yè #    Modular 0-based the current digit into it:
#     2→n%7; 3→reverse(n); 4→1n%n
}         #   Close the if-else statement
}           #  Close the loop
ˆ          #  Pop and add the final value to the global array as well
¯         #  Push the global array
J        #  Join it together to a single string
Q       #  Check whether it equals the (implicit) input-integer
}1ª           # After we've found a result: append a 1
è          # Modular 0-based index into the "%!+~"-string:
#  1→!; 2→+; 3→~; 4→%
# (after which this list of characters is output implicitly as result)

• »slow« as in »times out in input 12«, but is gets my upvote as I doubted golfing languages could crack the 50-byte-border on this. Commented Dec 11, 2023 at 10:08
• @Philippos Welp, it's at least able to output the first ten test cases and example. I've had 'slow' programs before on other challenges that could barely output the first single test case. ;) Commented Dec 11, 2023 at 10:17

# JavaScript (Node.js), 121 119 bytes

f=(n,a='',b,c=6,...s)=>n!=b?f(n,...s,a+'+',b,c+7,a+'-',b,+[...c+''].reverse().join,a+'%',b,('1'+c)%c,a+'!',[b]+c,6):a


Try it online!

Modified from my https://codegolf.stackexchange.com/a/265841/

• Seems theoretically fine, but already crashes on input 5 Commented Dec 11, 2023 at 9:57
• @Philippos Consumes too much stack. See Arnauld's solution for space-saving solution
– l4m2
Commented Dec 11, 2023 at 10:36
• @Philippos ulimit -s unlimited; node --stack-size=99999 ea.js outputs +++%%!
– l4m2
Commented Dec 11, 2023 at 10:42

# Jelly, 45 43 bytes

¹©ṃ“Ṿ;ɼ6“+7“D1;Ḍ%ṛṛ?“ṚḌ”v@ƒ6®Ḋ⁼
1ç1#ṃ“!+%~”


Try it online!

Since it’s permissible to output garbage to STDOUT while returning the actual answer as the pair of link’s return value, this is one byte shorter than the previous version which avoids doing so.

A pair of links called as a monad with a decimal string argument (e.g. "5") and returning a string program in !+~% golfed to output the relevant number. Relatively slow, brute force solution.

Originally got stuck for any programs that included % on 0, but now fixed at the cost of three bytes (which I then managed to shave off another way!)

• Not relatively slow, but absolutely slow: TiO times out on input 5. (-; I have no supercomputer to verify it, so I simply trust you. Commented Dec 12, 2023 at 6:14
• @Philippos there was actually a bug related to the way Jelly handles 10%0 and which meant it got into an infinite loop. Now fixed at a cost of 3 bytes - thanks for pointing out! Commented Dec 12, 2023 at 8:56
• This proves that I can trust you! (-: The performance is now similar to other solutions. I'm not sure why solutions seem to scale worse than 5^n Commented Dec 12, 2023 at 9:49

# Charcoal, 79 65 bytes

⊞υ⟦ω⁶ω⟧Ｆυ¿¬ⅈ¿¬⌕ιθ⊟ι«≔§ι¹ηＦ⪪⟦η⁻⁶η!ω⁷+ω⁻⮌ηη~ω∧η⁻﹪ＸχＬηηη%⟧³⊞υＥκ⁺λ§ιμ


Try it online! Link is to verbose version of code. Explanation: Based on @bsoelch's Python answer.

⊞υ⟦ω⁶ω⟧Ｆυ


Start a breath-first search with a state with no output, an accumulator of 6 and no commands yet.

¿¬ⅈ


Stop when a solution is found.

¿¬⌕ιθ⊟ι«


If a solution is found then print it, otherwise...

≔§ι¹η


Extract the current value from the state.

Ｆ⪪⟦η⁻⁶η!ω⁷+ω⁻⮌ηη~ω∧η⁻﹪ＸχＬηηη%⟧³


Create a list of updates, representing a string to output, an amount to add to the current value, and a command to execute, and split the list into groups of three elements.

⊞υＥκ⁺λ§ιμ


Add each group pairwise to the original state, creating four new states to be processed.

• +1 It can really handle all test cases without timeout except for 805 (-: Commented Dec 11, 2023 at 10:23
• @Philippos Well, it's exponentially slow in the length of the output...
– Neil
Commented Dec 11, 2023 at 10:53

s%x=x++s%[(c++[p],x,y)|(c,a,o)<-x,(p,x,y)<-zip3"!+~%"[6,a+7,read$reverse$s a,read('1':s a)moda][o++s a,o,o,o++['-'|a<1]]]
f n=[c|(c,_,o)<-show%[("",6,"")],o==n]!!0


Attempt This Online!

# Python, 156 bytes

-2 bytes, thanks to STerliakov

simple brute force approach, takes input as a (decimal) string

def f(N):
s="";S=[(6,s,s)]
while s!=N:(a,b,s),*S=S;A=str(a);S+=[(6,b+"!",s+A),(a+7,b+"+",s),(int(A[::-1]),b+"~",s),(a and int("1"+A)%a,b+"%",s)]
return b


Attempt This Online!

• Very smart, but you should get rid of the doubled spaces for indenting. Commented Dec 11, 2023 at 7:48
• You can do (a,b,s),*S=S instead of .pop(0) for -2. Commented Dec 12, 2023 at 0:01