The goal is to write a program that encodes an other program (input) with the fewest character possible.


  • The score is equal to the different number of characters needed for the output.
  • Lower score is better.


  • No target languages with a limited set of commands. (No Brainf**k, Whitespace etc)
    Edit: I mean at least 26 significant characters, A doesn't change the way a brainf**k program operates, so you can't count this character. Same applies to whitespace.
  • The target language must exist at the time where this question is written.
  • You have to include a small explanation how you achieve your score.
  • The input program is valid.
  • The encoded program must be a valid program in the same language as the input.
  • The encoded program must do the same job as the original program.
  • Your encoder must work for every valid program in that language.
  • Include some sample input and output.


  • The encoder might be written in any language, not only in the language it targets.
  • This is not , readable programs are encouraged.
  • The great goal is to see how many different characters are needed to write anything in that language. I disallowed BF etc because there would be no challenge.
  • This was inspired by Print a string in as few distinct characters as possible, you could take it as for that question.


In Java, you can use \uXXXX instead other characters. A valid entry encodes every character from the input this way. This would have a score of 18. (\ 0-9a-f)

Code in Tcl, encodes a Java program:

set res {}
foreach char [split [read stdin] {}] {
    append res [format \\u%04x [scan $char %c]]
puts $res
  • 2
    \$\begingroup\$ With you Java score and your encoder: I don't speak much Tcl, but doesn't gets read a single line of input only? And you missed the u in your encoder (but on the other hand you don't need the space and thus the score remains the same). \$\endgroup\$
    – Howard
    May 15, 2013 at 4:40
  • 9
    \$\begingroup\$ Don't all programming languages have a "limited set of commands"? Where do you draw the line? \$\endgroup\$
    – jpjacobs
    Sep 15, 2014 at 10:53
  • 5
    \$\begingroup\$ I'm voting to close this because it has a broken victory condition patched over by a very unclear ban on languages. If Unary wasn't banned, it'd score 1. If brainfuck wasn't banned, it'd score 7 (note that the language itself naturally has 8 commands + 248 comment characters). So where's the line between naturally having too few commands, and having enough to be legitimate. \$\endgroup\$
    – user62131
    Dec 28, 2016 at 11:10
  • 3
    \$\begingroup\$ Even languages like Python have a limited set of commands. You can't "make a new one", you simply create a new function or something, but the reserved words stay the same. The definition of "command" is unclear. The question could possibly be fixed by not limiting languages (just don't upvote trivial answers), and requiring that the set of characters used must be a proper subset of those in the language. \$\endgroup\$
    – mbomb007
    Dec 28, 2016 at 14:28
  • 1
    \$\begingroup\$ "at least 26 significant characters" seems to still allow a Beatnik-based answer with a score of 2... or even a Lenguage-based answer with a score of 1! (Neither language truly ignores any characters: Beatnik splits a program into chunks of consecutive alphabetical characters and executes commands based on their Scrabble scores, and a Lenguage program encodes a brainfuck program in its length disregarding any other information.) \$\endgroup\$ May 28, 2019 at 23:23

10 Answers 10


Python -> Python, 8 distinct characters

def minimal_python(input_code):
    """Convert Python code to minimal Python code."""

    # Create a list of the ordinal numbers of <input_code>'s characters.
    # '%' signs have to be treated specially and are represented with -1.
    ords = []
    num_escaped_chars = 0
    for char in input_code:
        if char == '%':
            num_escaped_chars += 1

    modulo_sign_escape = '%' * 2**num_escaped_chars
    def formatters():
        num_escaped_chars_so_far = 0
        for o in ords:
            if o == -1:
                yield modulo_sign_escape
                yield '%' * 2**num_escaped_chars_so_far + 'c'
                num_escaped_chars_so_far += 1
    format_str = "'" + ''.join(formatters()) + "'"

    values_str = ''.join('%' + '-~'*o + '0' for o in ords if o != -1)

    return 'exec' + format_str + values_str

This uses modulo formatting to rebuild the input string. For example, print 1 results in this program:


In theory you can encode any program like this, but the resulting program will always have more than 2n characters, where n is the number of characters in the input, not including % symbols.

  • \$\begingroup\$ The lower bound of the resulting program is 2**n+3*n-1 + 6 characters, including all input characters (if you assume every character is a NUL byte). This is taken from OEIS A132074, plus 6 for exec''. If you assume characters must be printable ASCII, then the lower bound is higher. repl.it/EHEN \$\endgroup\$
    – mbomb007
    Oct 26, 2016 at 19:09
  • 1
    \$\begingroup\$ There's another answer (on another challenge -- unfortunately, there are too many similar challenges) that takes only 7 bytes. codegolf.stackexchange.com/a/110722 \$\endgroup\$
    Jul 26, 2020 at 13:14

GolfScript / GolfScript, score 4


The encoder itself is a GolfScript program which takes the original code on STDIN and transforms it into a sequence of characters ',+~. This output itself is valid GolfScript code which performs the same operations as the original version.

The basic method consists of an encoding of the code as a string (using chars ',+, see below) and then evaluate this string using the eval command ~.

If one concatenates any string together with an array of numbers in GolfScript the numbers are converted to code points and the result is a string itself. Thus the string encoding simply builds a list of numbers (from the code points of the input code) and then concatenates all those with an empty string.


The input code


is translated into (note: line breaks and comments added for readability)

# initialize an empty array []

# append number 34 (length of string ',,, ... ,,,')

# ... other numbers

# result is array [34 104 105 34 10 112]

# append empt string, i.e. convert array to string (results in "\"hi\"\np")

# evaluate

CJam -> CJam, score: 3

CJam is newer than the question so it's not eligible to win.


It uses ')~. ') is the character ), and each extra ) increments it by one. ~ can evaluate a character or a string. The complete program is evaluated after concatenating all the characters by evaluating +. And an integer of the character value and a number-to-character operation is evaluated for each character less than ).



is translated into:




is translated into:


APL (score: 10)


Characters used in encoding: ⍎⎕AV[(⍴⍬)]

The APL program to encode must restrict itself to the APL charset and not use any extra Unicode.

Encoding for the program 42 (which outputs the answer to Life, the Universe, and Everything):


How it works: is the empty list, ⍬⍬⍬⍬ is therefore a list of four empty lists, ⍴⍬⍬⍬⍬ is the length of the list of four empty lists, which is four. Dyadic is reshape, so the length-of-list-of-lists instructions must be wrapped in parenthesis, giving the final encoding of character number four as (⍴⍬⍬⍬⍬).

These numbers are then looked up in ⎕AV which is the character set, and executes the resulting string.

(At first sight it looks like the score could be brought to 9 by using ⎕UCS instead of ⎕AV and saving [], but that doesn't work, because (⍴⍬)(⍴⍬) is a list of lists of scalars, i.e [[1], [1]] instead of the [1, 1] that would be required, and working around that would require interspersing the encoded values with commas, bringing the score back up to 10.)


Lenguage, score 1

The program consists of \$1{,}517{,}807\$ of any characters. These can be any characters you want, as Lenguage only depends on the length of a program. This does not break rule 1 as all characters are significant in Lenguage because of this fact.

This is one of the extremely few useful Lenguage programs that fits into the observable universe. Here is one of the \$1{,}114{,}112^{1{,}517{,}807}\$ possible Lenguage self-encoders.


Lenguage starts by calculating the program's length and converting it to binary. 1517807 in binary is 101110010100011101111. Next, it left-pads that number with zeros until the length of that number is a multiple of three. The length of 101110010100011101111 is 21, which is already a multiple of three, so we don't need to worry about this. After that, it splits it into chunks of three. This becomes 101 110 010 100 011 101 111. Finally, it is translated to BF using this simple table:

BF Translated Lenguage
+ 000
- 001
> 010
< 011
. 100
, 101
[ 110
] 111

And then evaluated as BF code. Here, 101 110 010 100 011 101 111 becomes ,[>.<,]. Here's what it does:

,[>.<,]  # full program
,        # input* to current cell
 [    ]  # while current cell is nonzero...
  >      # move pointer right
   .     # output current cell as a char
    <    # move pointer left
     ,   # input to current cell

This outputs a null byte for every character inputted. This doesn't change the execution of the inputted program since, as I said, the program is only dependant on the length of the program. Why a null byte, you ask? Because the tape initially starts out filled with zeros, and it's easier to just output the null byte that can already be output from the second cell than to set the second cell to some other value and output that every time. If you don't understand, here's an example:

Say the input is \$23{,}855\$ $s. This is one of the many variations of a cat program in Lenguage. It decodes to ,[.,], which is the standard BF cat. Here's the tape through each command:

36 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
36 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
[> .
36 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0


As you can see, each . command ends up on a 0, outputting a null byte for each character inputted.

*This program assumes that EOF is a null byte.


RProgN, 7 Distinct Characters, Noncompeting

RProgN is newer than this question.

' do.Lc

Convert the program to 'oooo...' L c 'ooooo...' L c 'oo...' L c . . . do, where each 'oo...' represents the character code in o's, surrounded by apostrifies to make a string out of them. L c then turns them into a number constant. After all the strings are placed on the stack, a chain of .'s equal to the amount of characters in the encoded string minus one rebuild the encoded string, and do executes it.

Encoder, also written in RProgN.

'oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' L c 'ooooooooooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooo' L c 'oooooooooooooooooooooooooooooooooooooooooooooo' L c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . do

Try it online!


Ruby -> Ruby, 8

#Convert a number from 0 to 255 to the form "111+11+11+1+1+1"
def byte_to_ones(byte)
  output = []
  ones = [111,11,1]
  ones.each do |one|
    while byte>=one

bytes = $<.each_byte.map { |byte| byte_to_ones(byte) }

puts "eval''<<#{bytes.join('<<')}"


puts "Hello, world!" => eval''<<111+1<<111+1+1+1+1+1+1<<111+1+1+1+1+1<<111+1+1+1+1<<11+11+1+1+1+1+1+1+1+1+1+1<<11+11+11+1<<11+11+11+11+11+11+1+1+1+1+1+1<<11+11+11+11+11+11+11+11+11+1+1<<11+11+11+11+11+11+11+11+11+1+1+1+1+1+1+1+1+1<<11+11+11+11+11+11+11+11+11+1+1+1+1+1+1+1+1+1<<111<<11+11+11+11<<11+11+1+1+1+1+1+1+1+1+1+1<<111+1+1+1+1+1+1+1+1<<111<<111+1+1+1<<11+11+11+11+11+11+11+11+11+1+1+1+1+1+1+1+1+1<<11+11+11+11+11+11+11+11+11+1<<11+11+11<<11+11+11+1<<1+1+1+1+1+1+1+1+1+1

Implements the Ruby solution given in the linked problem and replaces I/O with eval.

  • \$\begingroup\$ It was already linked in the question body; I wasn't using your comment. It's non-trivial to port answers over from there since you need to reverse-engineer them. \$\endgroup\$
    – histocrat
    May 15, 2013 at 15:34
  • 1
    \$\begingroup\$ I missed the reference to that question in the question body. I still don't think it's very interesting to just transform answers from it, but I withdraw my previous comment with apologies. \$\endgroup\$ May 15, 2013 at 16:04

Knight, score 5 4


Using the ASCII function, we can assemble arbitrary strings using +A(whitespace)1. However, since we know that all Knight programs will always be printable ASCII, tab, CR, or LF, we can always assume codepoints will be >= 9.

Therefore, to avoid whitespace, we can use EVAL.

+ can be used to both concatenate strings and do addition, A converts an integer to a string with its ASCII value, and 1 is used to add a bunch of 1's together to get any non-zero integer (strings with null bytes are illegal in Knight).

For example, if we wanted a string with a tab (ASCII 9) followed by a newline (ASCII 10) we would do this:


Now, we can simply encode a Knight program using this method and evaluate it with E.

Here is the conversion program in Knight. It adds a leading newline and leaves out the trailing newline, but otherwise encodes a functionally equivalent program.

This could be further optimized if we used 111 and 11, but this isn't despite the question being tagged it...

# start with empty string
; = acc ""
# slurp the entirety of stdin and concatenate with newlines
    : = acc + + acc ASCII(10) tmp
# First output the E to evaluate the next expression
# note: #"# is just to fix syntax highlighting
; OUTPUT("E\") #"#
# Now output length - 1 `+`'s to build the string one ASCII at a time
; OUTPUT(+ * "+" (- LENGTH(acc) 1) "\") #"#
# Now loop through the string
: WHILE(acc)
    # Grab the ASCII value of the first character in acc
    ; = char ASCII(acc)
    # snip off the first character of acc
    ; = acc SUBSTITUTE(acc 0 1 "")
    # output the ASCII keyword
    ; OUTPUT("A\") #"#
    # output n - 1 pluses
    ; OUTPUT(+* "+" (- char 1) "\") #"#
    # output n ones
    : OUTPUT(+*"E1" char "\") #"#

05AB1E, 8 4 distinct bytes


No TIO of the actual program, since the output would be way too big. It basically encodes the input-program into a program using the approach I've also used in the Fewest (distinct) characters for Turing Completeness challenge.

Try it online (with ƒ„.g}¤…B.V replaced with "D>gB.V" so we push the number instead of that many .g or try it online (with ® replaced with 9 as an example).


[                            # Start an infinite loop:
 „)\ì                        #  Prepend ")\" in front of the (implicit) input
     Nú                      #  Pad it with the loop-index amount of leading spaces
       ₅ö                    #  Convert it from a base-255 string to a number
         ©                   #  Store this number in variable `®` (without popping)
          g₅Qi               #  If the length of this number is 255:
              ®ƒ„.g}         #   Push `®` + 1 amount of ".g" to the stack
                    ¤        #   Tail (without popping): pushes "g"
                     …B.V    #   Push "B.V"
                         J   #   Join the stack together
                          ?  #   Output it without trailing newline
                           q #   And stop the program

This will produce a program with the 4 distinct bytes .gBV in the following format:

Loads and loads of .g to push a huge number. Then one additional .g+g to push 255, followed by B.V.

  • Loads of .g: Push the amount of items on the stack, which will become one larger every time, where only the last two are relevant
  • g: Pop the top number, and push its length (which will always be 255)
  • B: Convert the large number to base-255, resulting in the original input-program with prepended )\, to clean the stack from all the numbers we've pushed with .g () wraps the entire stack into a list and \ discards it)
  • .V: Execute it as 05AB1E code

Try such a program for (with the many .g replaced with a huge number plus additional D>). will push the lowercase alphabet & palindromizes it.


Julia 0.7, score 12

function f(a)
    u = unique("eval(parse(-*))")
    d = Dict{Union{Char,Int},String}(u .=> repr.(u))

    while a ⊈ keys(d)
        d2 = empty(d)
        for (k1,v1) in d
            for (k2,v2) in d
                    d2[k1-k2] = "($v1-$v2)"

    if length(a) == 1
        return "eval(parse(*($(d[a[1]]))))"
    elseif length(a) > 1
        return "eval(parse(" * join(getindex.([d],[a...]),'*') * "))"
        return ""


Try it online!

  • the 12 used characters are eval(prs-*')

  • parse("string") parses a string into an expression (AST)

  • eval evaluates an expression

  • we use character arithmetic to compute any character ('b'-'a'==1, 'b'-1=='a')

  • characters are combined into a string with multiplication ('a'*'b'=="ab")

  • d stores every character and number for which we have found a representation with the allowed characters

  • every combination of d[k1]-d[k2] is computed and added to d until all the characters of the input are found

  • in Julia 1.x, parse is replaced with Meta.parse, which would add 3 to the score

  • there is a warning in stderr due to the usage of parse instead of Meta.parse, which can be disabled with --depwarn=no if it is a problem for this challenge


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.