20
\$\begingroup\$

Your challenge, should you choose to accept it, is to write a program in a language of your choice that, when given a string (limited to printable ASCII) as input, outputs a new program in the same language that outputs that string without using any characters from that string in the code.

But this task is impossible as-is in many languages; for example, if the string to print contains every ASCII character. So instead, your submission will choose a subset of printable ASCII which is guaranteed not to be in the input. Your score will be the size of the set, with lower score being better, and shortest code length (in bytes) as a tiebreaker.

An example solution might be the following:

Python, 64 bytes / score 17

lambda s:"print('\\"+'\\'.join([oct(ord(c))[2:]for c in s])+"')"

Restricting the set print()'\01234567.

Now that's enough dawdling—go program!

Rules / clarifications

  • "Same language" includes any compiler flags used in the submission.
  • The outputted program should be a full program with output on STDOUT.
\$\endgroup\$
11
  • 1
    \$\begingroup\$ @UnrelatedString I don't know what you mean. The printable ASCII thing is just that you can assume the input string will always be printable ASCII, the output can be whatever you want. \$\endgroup\$ Commented Oct 31, 2023 at 1:32
  • 2
    \$\begingroup\$ @Jonah I had never written the word out before and tried to look it up but I didn't find the right spelling, thanks :) \$\endgroup\$ Commented Oct 31, 2023 at 1:44
  • 1
    \$\begingroup\$ Must be a full program, will clarify \$\endgroup\$ Commented Oct 31, 2023 at 3:16
  • 1
    \$\begingroup\$ »Printable« refers to the regex [:print:] class (ASCII range 0x20–0x7E)? Thus, it includes the whitespace 0x20, but not the TAB 0x09? \$\endgroup\$
    – Philippos
    Commented Nov 14, 2023 at 7:33
  • 1
    \$\begingroup\$ @Philippos Yup. \$\endgroup\$ Commented Nov 14, 2023 at 11:47

31 Answers 31

12
\$\begingroup\$

Python, 121 90 bytes / score 3

lambda s:f"print({'+'.join('chr('+'+True'*ord(c)+')'for c in s)})"

Attempt This Online!

-31 thanks to l4m2

NFKC normalization! The only reserved characters are (+), and everything else is done with identifiers written in fullwidth characters.

Builds codepoints up as sums of True.

It feels almost possible to go down to 2... almost. Constructing the codepoints with just () seems maybe doable with some kind of str/repr layering, but it takes either + or ,= to print it all on one line... and I also have half a mind to cut print out of the picture, but it seems like it would take ,. to go the open(1, 'w') route.

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

Jelly, 19 11 10 bytes / score 0

O”‘ẋp”Ọj”®

Try it online!

-1 thanks to Jonathan Allan

Encodes arbitrary strings as programs with no ASCII whatsoever, using increment spam for charcodes and unparseable nilads to both print and reset to 0.

O             Codepoints of the input.
 ”‘ẋ          Repeat ‘ (increment) that many times for each codepoint.
    p”Ọ       Append Ọ (convert from codepoints) to each.
       j      Join on
        ”®    the register nilad (0 unless set otherwise).
\$\endgroup\$
1
  • 2
    \$\begingroup\$ Save one byte more with j⁾⁹Ḃ -> j”®. \$\endgroup\$ Commented Oct 31, 2023 at 23:53
8
\$\begingroup\$

Brain-Flak, 78 bytes / score 2

{({}<>)<>}<>{<>(((((()()()()()){}){}){})())<>{({}[()])<>((({}[()])()))<>}{}}<>

The input cannot contain either of ().

Try it online!

And readable version:

# Reverse the input
{({}<>)<>}
<>

# For each character...
{
    # Push '()' to alternate stack
    <>
    (((((()()()()()){}){}){})())
    <>

    # While true...
    {
        # Subtract one from the character on top of the stack
        ({}[()])

        # On the alternate stack...
        <>
        # Remove the '(' on top, and insert '()' underneath it, then put it back
        ((({}[()])()))
        <>
    }{}
}<>
\$\endgroup\$
7
\$\begingroup\$

;#+, subset size 2, 40 bytes

;;;;;~+++++++>~;~++++:>*(-(;~<#~):<#-*:)

Try it online! Input is terminated with a null byte. Assumes the input does not contain ; or #.

Explanation

As this is a repost of my answer to another question from 2017, you can find a detailed explanation there. On a high level, it just generates constants for ; and #, and for each character in the input, the program outputs that many ;, followed by a #.

;#+ being a superset of ;# allows us to reuse the code from the linked challenge without modification.

\$\endgroup\$
6
\$\begingroup\$

Charcoal, 12 bytes, score 0

⭆S⁺´℅´L×´¶℅ι

Attempt This Online! Link is to verbose version of code. Accepts any Unicode character other than NUL and ℅L¶ that the output uses (the last one being \n in Charcoal's code page; the resulting program can't properly print newlines, but you can use \r instead). Run the sample output: Try it online! Explanation:

 S              Input string
⭆               Map over characters and join
   ´℅´L         Literal string `℅L`
  ⁺             Concatenated with
        ´¶      Literal string `¶` (bare `¶` would be `\n`)
       ×        Repeated by
           ι    Current character
          ℅     Take the ordinal
                Implicitly print

The resulting program contains a number of strings of the form ℅L¶¶¶...¶¶¶ each of which outputs the Unicode character with the code point given by the number of s.

Since the resulting programs get long quickly, here's a longer program that outputs shorter programs:

⭆S⁺´℅⍘℅ι”y⁰¹²³⁴⁵⁶⁷⁸⁹

Try it online! Link is to verbose version of code. Accepts any Unicode character other than NUL and ℅⁰¹²³⁴⁵⁶⁷⁸⁹ that the output uses, although the restriction on \n still applies. Run the sample output: Try it online! Explanation: Converts the ordinals of the input characters into Charcoal's digits (which aren't printable ASCII), with telling the resulting program to convert them back into Unicode.

\$\endgroup\$
3
  • \$\begingroup\$ If it can’t properly print new lines, then wouldn’t that have to be in the character set? \$\endgroup\$ Commented Oct 31, 2023 at 10:28
  • \$\begingroup\$ @noodleman Not sure what you're asking. If you want the output to be broken into separate lines then you need to use the Mac line break character \r instead of the Unix \n. The generated program, when interpreted in Charcoal's code page, contains newlines anyway, so they're part of the banned set, so to speak, even though the program only requires the input to be printable ASCII. \$\endgroup\$
    – Neil
    Commented Oct 31, 2023 at 11:18
  • \$\begingroup\$ Oops, forgot that newlines aren't printable ASCII. \$\endgroup\$ Commented Oct 31, 2023 at 11:36
5
\$\begingroup\$

Ruby, 92 50 bytes, score 8 7

->e{'$><<$==""<<'+(e.bytes.map{|x|[1]*x*?+}*"<<")}

Try it online!

How

In Ruby, the string operator << converts an integer to a codepoint, and appends the corresponding character.

Starting with the empty string, we can append all characters of the original string as numbers, and send the result to standard output ($>). Using $= (deprecated variable warning) to avoid wrapping the string in brackets, and saves 1 character.

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

Vyxal Ds, 67 bitsv2, 8.375 bytes, score 0

C\›*`ø⟇₴`+

Try it Online!

Bitstring:

0101011101110101111010001011001000010010000000010100011110100110010

The set is the entire vyxal code page minus ⟇₴ø›. Vyxal's code page contains printable ascii in the same spots as Unicode which is very convenient.

Explained

C\›*`ø⟇₴`+­⁡​‎‎⁡⁠⁡‏‏​⁡⁠⁡‌⁢​‎‎⁡⁠⁢‏⁠‎⁡⁠⁣‏⁠‎⁡⁠⁤‏‏​⁡⁠⁡‌⁣​‎‎⁡⁠⁢⁡‏⁠‎⁡⁠⁢⁢‏⁠‎⁡⁠⁢⁣‏⁠‎⁡⁠⁢⁤‏⁠‎⁡⁠⁣⁡‏⁠‎⁡⁠⁣⁢‏‏​⁡⁠⁡‌⁤​‎‎⁡⁠⁢⁢‏⁠‎⁡⁠⁢⁣‏‏​⁡⁠⁡‌⁢⁡​‎‎⁡⁠⁢⁤‏‏​⁡⁠⁡‌­
C           # ‎⁡Convert to a list of Unicode code points
 \›*        # ‎⁢Repeat › per each character 
    `ø⟇₴`+  # ‎⁣And add this string 
     ø⟇     # ‎⁤  Index into the vyxal code page 
       ₴    # ‎⁢⁡  Print without a newline. This makes the top of the stack empty. 
💎

Created with the help of Luminespire.

\$\endgroup\$
3
  • \$\begingroup\$ Uh, not quite. Don't ask me why it's like that \$\endgroup\$
    – emanresu A
    Commented Oct 31, 2023 at 11:15
  • \$\begingroup\$ ^ is a bug, it's in the process of being fixed. \$\endgroup\$
    – lyxal
    Commented Oct 31, 2023 at 12:04
  • \$\begingroup\$ This has been fixed \$\endgroup\$
    – lyxal
    Commented Oct 31, 2023 at 12:31
3
\$\begingroup\$

Java, 202 bytes, score 18

interface M{static void main(String[]a){("interface I{static void main(String[]a){System.out.print(\""+a[0].replaceAll("\\\\|\"","\\\\$0")+"\");}}").chars().forEach(c->System.out.printf("\\u%04x",c));}}

Attempt This Online!

Java interprets unicode escapes \uABCD everywhere, not only in String literals. This way, we can write a program using only the characters \u0123456789abcdef.

\$\endgroup\$
1
  • \$\begingroup\$ Can be improved using Java 21's free standing main \$\endgroup\$
    – Seggan
    Commented Oct 31, 2023 at 18:30
3
\$\begingroup\$

Javascript with JsFuck lib, 6 restricted, 43 bytes

x=>JSFuck.encode(`x=>`+JSON.stringify(x),1)
\$\endgroup\$
3
\$\begingroup\$

Brainfuck, 49 bytes / score 3

,[>>--[<+>++++++]<<[->.<]>+++.>++++[<++++>-]<.>,]

Attempt This Online!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Score 2 is possible if the interpreter wraps around at 256 \$\endgroup\$ Commented Nov 2, 2023 at 11:52
  • \$\begingroup\$ -3 bytes, subset: -<. \$\endgroup\$ Commented Nov 13, 2023 at 19:54
3
\$\begingroup\$

Python, 87 bytes, score 9 (ASCII only code)

See Unrelated String's solution for a lower score by using non-ascii characters

-4 bytes, thanks to noodle man
-9 bytes, thanks to l4m2


def f(s):print(f"exec({'+'.join('chr('+'+1'*ord(c)+')'for c in f'print({repr(s)})')})")

Attempt This Online!

encodes string using exc()hr1+

Explanation

Encodes string as exec(chr(1+...+1)+chr(1+1+...)+...)

The executed code is print(S) with S being the string-representation of the input. The characters in the string are represented as sums of 1's


Python, 85 bytes, score 11

def f(s):print(f"exec({'+'.join(f'chr(0b{ord(c):b})'for c in f'print({repr(s)})')})")

Attempt This Online!

encodes string using exc()hr0b1+

\$\endgroup\$
2
2
\$\begingroup\$

JavaScript, 66 bytes, score 15

Using the restricted set alert`\01234567:

s=>"alert`"+s.replace(/./g,c=>"\\"+c.charCodeAt().toString(8))+"`"

Uses deprecated octal string literals and alert with a tagged template function call. I was worried that alert would stringify the tagged template as [Object object] but fortunately for me that did not happen.

I wrote this on my phone so I can’t insert a stack snippet at the moment.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ I’m pretty sure the optimal solution is a JSFuck subset \$\endgroup\$ Commented Oct 31, 2023 at 13:01
2
\$\begingroup\$

05AB1E, score 0 (14 bytes)

Ç'ǝ×»“”ÿ”Åγιнç

Output of the output program is a list of characters.

Try it online.
Try the outputted program online. (Feel free to remove the Join in the footer to see the actual list output.)

Explanation:

Ç              # Convert the (implicit) input-string to a list of codepoint-integers
 'ǝ           '# Push string "ǝ"
   ×           # Convert each codepoint to a string with that many "ǝ"
    »          # Join this list of strings with newline delimiter
     “”ÿ”Åγιнç # Push (dictionary) string "”ÿ”Åγιнç",
               # where the `ÿ` is automatically replaced with the earlier string
               # (after which the result is output implicitly)
”ǝǝǝ...ǝǝǝ
...
ǝǝǝ...ǝǝǝ”     # Push (dictionary titlecase) string with "ǝ" and newlines
Åγ             # Run-length encode it; pushing pair ["ǝ","\n"] and a list of lengths
  ι            # Uninterleave the list of lengths into two parts
   н           # Pop and leave just the first part (the lengths of the "ǝ"-lines)
    ç          # Convert each from a codepoint-integer to a character
               # (after which this list of characters is output implicitly as result)

Some notes:

  1. ǝ is used, since 'ǝ× nor 'ǝǝ are dictionary words. But any non-ASCII character that doesn't form dictionary words would be fine here.
  2. and are used to prevent the ASCII-quote ". Luckily, none of ”ǝ/ǝǝ/”Å/Åγ/γι/ιн/нç are dictionary words.
  3. An approach similar to the Jelly/Vyxal answers using an increment won't work in 05AB1E, since the increment-by-1 builtin is an ASCII-character: >.
\$\endgroup\$
2
\$\begingroup\$

Ly, Length 20 / Score 4

Input cannot have 4 characters 0`&o.

&ir[0u['`o,]p]"&o"&o

And at a high level, the code reads all input as codepoints, then converts each character to a 0 and as many "increment the top of stack" instructions as is necessary to get to the codepoint value. Then it appends &o to the end to print the entire stack as characters.

&ir                   - read input as codepoints, reverse stack
   [         ]        - loop once for each char on the stack
    0u                - push a "0" onto the stack
      [    ]          - while number is >0
       '`o            - print "`" (the increment instruction)
          ,           - decrement the top of stack
            p         - delete the loop variable from the stack
              "&o"    - push "&o" (print whole stack instruction)
                  &o  - print stack

Try it online!

\$\endgroup\$
3
  • 1
    \$\begingroup\$ I fixed the formatting, click the edit history of your answer to see how to do it. \$\endgroup\$ Commented Nov 1, 2023 at 10:52
  • \$\begingroup\$ Thank you! I tried various incantations to get the backtick to live in a quoted string, but didn't think of the pattern you used. \$\endgroup\$
    – cnamejj
    Commented Nov 1, 2023 at 20:04
  • 1
    \$\begingroup\$ No problem. In general, wrap a string using N backticks in a row with N+1 backticks on either side. \$\endgroup\$ Commented Nov 1, 2023 at 22:53
2
\$\begingroup\$

Uiua, 22 bytes, score 4

⍜⇌'⊂@"⊂"&p-π\""+π

Try it!

restricted set is &p-"

this would be much easier if the implicit stack printing didn't put quotes around strings, as it stands i could not get rid of &p, either - or + for offsetting the codepoints, or ", $ , or @ and a lot of s

\$\endgroup\$
2
  • \$\begingroup\$ What set is restricted? \$\endgroup\$ Commented Nov 1, 2023 at 17:13
  • \$\begingroup\$ @noodleman i knew i was forgetting something... edited \$\endgroup\$
    – tzlil
    Commented Nov 1, 2023 at 17:15
2
\$\begingroup\$

brainfuck, 76 bytes/ score 2

+++++[->+++++++++<],[<+[+>+[->>+>+<<<]>>[-<<+>>]+>[<[-]>-]<[<.+.->-]<.<<]>,]

Try it online!

All brackets are <> balanced so the reordering tool should help

\$\endgroup\$
2
\$\begingroup\$

C (gcc), 171 bytes, score 14 main(){}prtf&+

#define f(c,d)for(k=c+1;k--;)printf(#d);
n;k;g(){f(n,main)}main(c){for(;c=~getchar(g());){f(,(a){)f(c+38?-2-c:9507,if(++a))f(,if\50)g(++n);f(,(printf(&a))\51{}})}f(,(){})}

Try it online!

Try Generated online!

\$\endgroup\$
1
  • \$\begingroup\$ I tried locally, without -w it's 414645 bytes of stderr \$\endgroup\$
    – l4m2
    Commented Nov 24, 2023 at 15:47
2
\$\begingroup\$

PHP, 43 bytes, score 5

Input cannot contain ;<=?~.

<?="<?=~".~ stream_get_contents(STDIN).";";

Try it online!

Uses the same approach as my Perl answer bitflipping the strings, but PHP doesn't need any quoting as the high-byte chars are considered a constant (in PHP < 8).

\$\endgroup\$
1
\$\begingroup\$

Julia 1.0, 75 bytes / score 5

!s="µ()=(µ(µ)=µ)"*join(("('µ'-('$('µ'-i+'µ')'-'µ'))" for i=s),'µ')

Try it online!

the used ascii characters are '()-=. Other characters used are µ (a lot) and ì to Ŋ depending on the needed characters.

creates a function that ouputs the string by concatenating Chars, which are constructed by substracting non-ascii characters, for example 'A' == 'µ'-116 == 'µ'-('ĩ'-'µ')

concatenation in Julia is *, which can be implied in some case. That's why we create the identity function µ(µ)=µ:

µ('a')µ('b') == µ('a')*µ('b') == 'a'*'b' == "ab"

\$\endgroup\$
1
\$\begingroup\$

Google Sheets, score 13 / 92 bytes

=let(p,join(,"=",sort("символ("&code(mid(A1,sequence(1,len(A1)),1))&")&")),left(p,len(p)-1))

Put the input in cell A1 and the formula in B1.

When the input is abc123, the formula gives this output:

=символ(97)&символ(98)&символ(99)&символ(49)&символ(50)&символ(51)

The set of printable ASCII in the output is 0123456789()&.

The output is a valid formula in Google Sheets in any locale, including Latin locales such as United States. When the output is evaluated as formula, its result is abc123.

The formula uses the equivalent of the char() function in Cyrillic, символ(), whose name doesn't match any Latin letters (console.log('символ'.match(/\w/))null).

\$\endgroup\$
1
\$\begingroup\$

Unary, \$8.71412 \times 10^{420}\$ bytes, score 1

…Obviously, I will not be posting the full code here. Or anywhere. It is 8714123138855978699360164050596229281826476597589481446286633953212548084711579903126530450262195558539773177853879595103615733973606156395440197295886222547053888870061749608029900423204725572303716359786086331805843402197818088474380787864934634643574154692137242860845559867854533001295180659830847166956220859057004333374262038608140098168588215568980939574816997785951406147471781245309306817118354877602371834815751 bytes long. That's a lot of bytes.

Handles all characters as input but 0, which is the only character that appears in the output. A rare case where Unary does not trivialize a challenge like this? I've had my eyes set on a non-trivial score 1 answer for a while, and Unary is a perfect candidate.

Here is the script I used to generate the program size, and here is the corresponding Brainfuck program (formatted with newlines for readability):

+>,>>>>>>+++>>>+<<<<<<<<<<[>>[-]+>[-]<<[>>>[-]>[-]+>[-]<<<<<+[>-<[>>+<<-]]>>[<<+
>>-]<[>>>-<<<<[-],[++>-<[>>+<<-]]>>[<<+>>-]<[<<->>-]]<-[>>+<<-]]>>[<<+>>-]<[>>[-
]+>[-]>[-]<<<<-]>>>>>[>>+[>[<-]<[->+<]>]>[->[>]>[>]+>+[<]<[<]>]+[<[>-]>[-<+>]<]<
<<<[<+>->>>>+[>[<-]<[->+<]>]>[>]+[<]+[<[>-]>[-<+>]<]<<<<]<[->+<]>[-<+>>-<]>[-<+>
]<<[->>+<+<]>>[-<<+>>>-<]>[-<+>]<<<[->>>+<+<<]>>>>-]+++<<<<<<-<]>>>>>>>>+[>[<-]<
[->+<]>]>[+++++++++++++++++++++++++++++++++++++++++++++++.>]

Assumes an interpreter with dynamic memory (right-infinite) and EOF = 0 (or 0x00 manually appended to the input).

Unfortunately, even this program is obscene, since we do still have 8-bit cells. We store the unary output program as a series of 1s on the tape, which grows exponential with the input size. As a proof of concept, you can Try it online! with input 0x02. This outputs some debug information to show that the corresponding program in Unary is 1 010 010 100 000 (corresponding to ++.>), which corresponds to the 5,280 0s which follow that debug information.

Explanation

Here is my fully commented corresponding Brainfuck program:

[-][
  ASSUMES:
   - Dynamic Memory Tape (Right-Infinite)
   - EOF = 0x00 and/or null terminated input

  for reference, the Unary bijection:
  | > corresponds to 000
  | + corresponds to 010
  | . corresponds to 100

  our desired output is Nx'0' characters, where
  |        +   +  ...  +   .   >   +   +  ...  +   .   >  ...
  | N = 1 010 010 ... 010 100 000 010 010 ... 010 100 000 ...
  |       {ord n.0 times}         {ord n.1 times}

  assuming dynamic tape memory (but finite cell size), since we need only to output
  in unary, we may store N as a unary integer in tape size
  
  our bit to unary algorithm can be expressed on a high level:
  | for each bit:
  |   n *= 2
  |   if bit:
  |     n++
  |   end if
  | end for
  
  we need to be able to stream bits from the input not proportional to the input size
  that is, there is a large, variable number of bits corresponding to each , input
  we will try to process this character-by-character instead of reading all the input
  and generating the corresponding bit string, and iterating over that afterwords, so
  as to hopefully avoid weird tape layouts
  
  assuming some procedure for emit, our algorithm works as:
  | emit 1
  | for each input character C:
  |   while C is not 0:
  |     emit 010
  |     C -= 1
  |   end while
  |   emit 100
  |   emit 000
  | end for
  | for each bit in unary representation, output '0'
  
  however, obviously, we do not procedure calls available to us. ideally, we linearize
  our loop to be in terms of processing emitted bits:
  | C = input
  | loop:
  |   if C == 0:
  |     emit_bits = 1 0 0
  |   elsif C == 255:
  |     emit_bits = 0 0 0
  |     C = input
  |     if C is EOF:
  |       break
  |     end if
  |     C = C + 1
  |   else:
  |     emit_bits = 0 1 0
  |   end if
  |   times 3:
  |     double bitstring
  |     if cur_bit:
  |       increment bitstring
  |     end if
  |     move_bit_right
  |   end times
  |   C -= 1
  | end loop
  
  we can abuse the fact our input is guaranteed to be printable ascii and use 255 (-1)
  as a state value to get an extra 3 bits per input character

  as for implementing this algorithm, our tape layout will be:
     0: L (looping counter for break)
     1: C (input character)
     2: t0 (temp)
     3: t1 (temp)
     4: e0 (emit bit)
     5: e1 (emit bit)
     6: e2 (emit bit)
     7: t3 (3 counter)
     8: 0 (0 padding)
     9: 0 (0 sentinel)
    10: 1 (start of unary representation)
]

real code starts here

+ set L
>, get input
>> move past temps
>>> move past e0 e1 e2
> +++ set counter
> > two 0s of padding
> + emit 1

debug initial unary representation
debug++++++++++++++++++++++++++++++++++++++++++++++++.------------------------------------------------
>debug++++++++++++++++++++++++++++++++.--------------------------------<

L < << <<< <<< < return to looping counter

[
  if else algorithm with (C t0 t1) tape layout
  C>
  temp0> [-]+ temp1> [-] C<< [
    IF C NOT ZERO
    >>
    >[-]  e0 = 0
    >[-]+ e1 = 1
    >[-]  e2 = 0
    <<< <<
    
    (temp0 temp1) = (1 0) at this point always so we can reuse them
    as long as they are that way to end with
    recall our if else algorithm requires t0 to be 1 initially anyway
    C+ test for c being 255 that is negative 1
    C[  {empty else}  temp0> - C< [temp1>>+C<<-]]
    temp1>>[C<<+temp1>>-]
    temp0<[
      {if 255 sentinel}
      e1>>>-  e1 = 0
      debug++++++++++.----------
      C<<<<[-]
      input ,
      here is where we need to detect EOF and set L accordingly
      we can use the same fact to reuse t0 t1 in our if statement
      C[
        ++ increment C
        temp0>-
        C<[temp1>>+C<<-]
      ]
      temp1>>[C<<+temp1>>-]
      temp0<[
        on EOF break by setting L to 0
        L<<-
        temp0>>
      temp0-]
      + restore temp0
      C<
  
      temp0>
    temp0-]
    C<
    restoration
    C-
    temp0>+
    <
  
  temp0> - C< [temp1>> + C<< -] ] temp1>> [C<< +temp1>> -] temp0< [
    IF C ZERO
    temp0
    > temp1
    >[-]+ e0 = 1
    >[-]  e1 = 0
    >[-]  e2 = 0
    <<<<<<
    temp0>>
  temp0-]
  
  debug contents of (e0 e1 e2)
  >>   debug++++++++++++++++++++++++++++++++++++++++++++++++.------------------------------------------------
  >    debug++++++++++++++++++++++++++++++++++++++++++++++++.------------------------------------------------
  >    debug++++++++++++++++++++++++++++++++++++++++++++++++.------------------------------------------------
  <<<< temp0 debug++++++++++++++++++++++++++++++++.--------------------------------
  
  >> e0
  
  ADVANCE THE TAPE
  >>>
  [
    >> seek to 0 sentinel
    +[>[<-]<[->+<]>]> seek right to first 1 in tape
    doubling loop
    [
      - erase current 1
      >[>] navigate to right border 0
      >[>] go past rightmost 1 on copy tape to second right border 0
      +>+  add two entries
      [<] go back to first right border 0
      <[<]> navigate to start of 1 tape
    ]
    tape to start was   e0 e1 e2  1 0  {a0 a1 a2 etc}
    tape to end is      e0 e1 e2  1 0  {0  0  0  etc}  0  {a0 a0 a1 a1 a2 a2 etc}
    +[<[>-]>[-<+>]<]< seek left to 1 sentinel
    <<< seek back to e0
  
    APPEND A ONE IF E0 IS NONZERO
    [
      <+> save to temp0
      - zero out to close loop
      append a 1
      >>>> seek to 0 sentinel
      +[>[<-]<[->+<]>]> seek to first 1 in tape
      [>] seek to end
      + append 1
      [<] seek to start
      +[<[>-]>[-<+>]<]< seek to count sentinel
      <<< seek back to e0
    ]
    <[->+<] add temp0 to e0 (either computes 0 plus 1 or 1 plus 0 so its idempotent)
    > focus back on e0
  
  
    permute e0 e1 e2 to e1 e2 e0
    [-<+>>-<]>[-<+>]<<[->>+<+<] swap{@1 @2}
    >>[-<<+>>>-<]>[-<+>]<<<[->>>+<+<<] swap{@2 @3}
    > refocus e0
  
    >>> seek to count sentinel
    - decrement
  ]
  reset counter +++
  END ADVANCE THE TAPE
  <<<<<
  C<-
  L<
]

>>>>>>>> move past last data entry
+[>[<-]<[->+<]>]> skip all 0s to our unary tape
for each one on the unary representation
[
  output a 0
  +++++++++++++++++++++++++++++++++++++++++++++++.>
]
\$\endgroup\$
1
  • \$\begingroup\$ Is its Lenguage version with NUL output shorter? And 0 is therefore allowed \$\endgroup\$
    – l4m2
    Commented Nov 19, 2023 at 6:54
1
\$\begingroup\$

Japt, 25 32 29 bytes, score 2 1

©"ºº»Â½{'ÄpUÌc}¹d¹ã½Ñ{ßU¯J}¹¬

Try it

Saved 3 bytes thanks to @Shaggy!

The only ASCII character that the output uses is d. I am 99% certain that there is no way to get arbitrary strings without using d.

I didn't think that score 1 was possible until I was looking through Japt's docs for a method that could concatenate strings or lists whose name was non-ASCII. When I wrote my first solution, I dismissed what I saw as not being usable for the purpose of creating arbitrary strings. However, when returning to this problem yesterday, I found the method ã.

ã returns all substrings of a string, optionally taking a length that the substrings must be of. But as it turns out, it also takes an optional second parameter which is prepended to the list of substrings.

This solution recursively generates the resulting program with a string literal containing the boilerplate for the connection of each letter.

The first step is ©, which does short-circuiting logical AND of the input and what follows. The result is that if the input is an empty string, it is returned, otherwise the program continues execution.

Now the string literal starts. The first bit is ºº»½Ñ, followed by an interpolation of the expression 'ÄpUÌc which essentially converts a character to the string Ä repeated the codepoint of the character times. Then follows the string ¹d¹.

  • This section creates the code to have an arbitrary character without using ASCII (except for d). A single character is generated using a similar technique to my previous solution by using long lines of »½ÑÄÄÄÄÄÄ…ÄÄÄĹd¹, which is essentially getting the character at codepoint 1+1+1+1...+1, plus a longwinded way to get out of using parentheses.

Next, the string ã½Ñ is the code to prepend the rest of the string.

The rest of the string's code is generated by recursing with the last character chopped off (ßU¯J).

Finally, the string ¹¬ will join each section from a list to a string.

\$\endgroup\$
1
  • \$\begingroup\$ Very nicely done! And you can get it down to 29 bytes \$\endgroup\$
    – Shaggy
    Commented Nov 15, 2023 at 14:42
1
\$\begingroup\$

MetaBrainfuck -x, 30 bytes / score 2 (+.)

43{_:+}{n:n{.}+++.---256n~{.}}

input as program argument

produces a Brainfuck program that prints a Brainfuck program that prints the Input, then executes that program

Explanation

43{_:+}                        ## output 42 times + (`_:` discards the loop counter)
       {n:                   } ## for each character `n` in the input
          n{.}                 ## repeat `.` n times
              +++.---          ## increment by 3, print decrement by 3
                     256n~{.}  ## repeat `.` 256-n times

-x executes the generated Brainfuck program, which outputs a program that for each character C in the input increments C times prints then increments 256-C times resetting the cell back to zero.

Brainfuck Program created for input "Test" (the output for the program will be the result of executing that Brainfuck program):

+++++++++++++++++++++++++++++++++++++++++++....................................................................................+++.---.................................................................................................................................................................................................................................................................................+++.---..............................................................................................................................................................................................................................................................................+++.---.................................................................................................................................................................................................................................................................+++.---............................................................................................................................................

Running MetaBrainfuck -x on the (uncommented) Brainfuck created by the output of the original program will execute the program without modification and print the input of the original program


MetaBrainfuck -x , 24 bytes / score 3 (+.>)

{43{_:+}{.}".>"{>{+}.}>}

input as program argument

produces a Brainfuck program that prints a Brainfuck program that prints the Input, then executes that program

Explanation

{                      }   ## for each character in the input
 43{_:+}                   ## output 42 +  ( `_:` discards the loop counter)
        {.}                ## print . char-code many times
           ".>"{     }     ## for each character C in ".>"
                >{+}.      ## output  > followed by C times + followed by a .
                      >    ## print >

the produced Brainfuck program then prints C times + followed by .> for each character C in the input, the -x flag the immediately executes that program.

Program created for input "Test":

+++++++++++++++++++++++++++++++++++++++++++....................................................................................>++++++++++++++++++++++++++++++++++++++++++++++.>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>+++++++++++++++++++++++++++++++++++++++++++.....................................................................................................>++++++++++++++++++++++++++++++++++++++++++++++.>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>+++++++++++++++++++++++++++++++++++++++++++...................................................................................................................>++++++++++++++++++++++++++++++++++++++++++++++.>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>+++++++++++++++++++++++++++++++++++++++++++....................................................................................................................>++++++++++++++++++++++++++++++++++++++++++++++.>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>
\$\endgroup\$
1
\$\begingroup\$

Zsh, score 12, 50 bytes

Set is 01234567$'\<.

for c (${(s..)1})l+="\\$[[##8]#c]"
<<<'<<<$'\'$l\'

Try it online!

Converts each character into \[N]NN octal, evaluated by wrapping the string in $' ' and printed with <<<.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Wouldn’t the score be 12, because of the <? \$\endgroup\$ Commented Nov 15, 2023 at 18:19
  • \$\begingroup\$ @noodleman yep, thanks! \$\endgroup\$ Commented Nov 21, 2023 at 6:07
1
\$\begingroup\$

Morsecco: 54 bytes, score 3

Being a three-symbol language, a meta-cat automatically reaches a score of 3:

> echo Test | morsecco '. . . - .-. -.- .- -.-. ... .  -.- - ---  -.-. ... ---'
.  -.-.-.. --..-.- ---..-- ---.-.. -.-.  -.- - ---
> morsecco '.  -.-.-.. --..-.- ---..-- ---.-.. -.-.  -.- - ---'
Test
  • . . Enters an Enter command
  • . - .-. Reads from stdin (special address T)
  • -.- .- Konverts from ·Text
  • -.-. ... Concatenates the dot and the converted input with two spaces for multi-token input
  • . -.- - --- is the multi-token input for the later Konvert to Text and Output
  • -.-. ... Concatenates this to the existing code
  • --- Output the code

Morsecco:  217  216 bytes, score 0

Yes, we can also do a zero-score version, because morsecco accepts alternatives for it's characters:

  • TAB can be used instead of whitespace
  • a long dash (unicode 0x2013) can be used as dash
  • the middle dot · (unicode 0x00B7) can replace the dot

Of course, this adds a lot of bytes:

.  -- . -- .  . . .-- . . . - .-. -.- .- -.-. ... .  -.- - ---  -.-. ... 
-- - -.-. - -.- .- . .-..... .- --.. ..
. .---. .- --.. --.
- .- . -........-..-- -- --.. --.
. -.--.--- -- --- --. ..
. -..-
-.- - . - .-- --.

The first line remains the same just installing an error handler to silently exit on the end of input to avoid testing for more bytes, but then we need to loop over the string, cutting one byte each time and translating it, because by now morsecco has no substitution command.

\$\endgroup\$
1
\$\begingroup\$

C (gcc), 200 192 184 211 203 bytes, score 17 16

#define P;printf(
#define Q{for(k=~i;k++P"a"))P
i;k;main(j,v)unsigned**v;{for(v++;i*4<strlen(*v);i++)Q"=a==a;");}P"main(){");for(;i--;)for(j=32;j--;)Q"+=");Q";");}if(i[*v]&1<<j)Q"++;");}}P"puts(&a);}");}

Try it online!

The input cannot contain aimnpstu=+;&(){}

This produces C programs of the form

a=a==a;
aa=a==a;
...
main(){
  a++;...
  aa++;...
  puts(&a);
}

Try it online!

Thanks to @l4m2 for score -1 and the note from @NoodleMan.

Less golfed version

#define P;printf(
#define Q{for(k=~i;k++P"a"))P
i;k;
main(j,v)unsigned**v;{
  for(v++;i*4<strlen(*v);i++)
    Q"=a==a;");
  }
  P"main(){");
  for(;i--;)
    for(j=32;j--;)
      Q"+=");
      Q";");}
      if(i[*v]&1<<j)
        Q"++;");
      }
    }
  P"puts(&a);}");
}

C (gcc) for Linux x86_64, 271 260 253 239 226 bytes, score 8

#define P;printf(
unsigned*b,x;i;main(l,v)int**v;{l=asprintf(&b,"j\1X\xbazokaj\1_耀ok%s^\xf\5Ã",v[1]);for(b[1]=b[3]=l-21;i*4<l;b++){P"mai");for(x=++i;x--P"n"))P"=");for(x='B:5\xc7';*b P"+%d",x),*b-=x)for(;*b<x;x/=10)P";");}}

Try it online!

The input cannot contain aimn=+1;

This produces C programs of the form

main=1+11+...;
mainn=1+1+11+111+...;
...

Try it online!

Such programs may require the compiler flag -zexecstack and may not work on some Linux distributions.

Now supports strings longer than 127 bytes.

Slightly less golfed

#define P;printf(
unsigned*b,x;
i;
main(l,v)int**v;{
  // push 1
  // pop rax
  // mov edx, <len of string>
  // push 1
  // pop rdi
  // call L1
  // <string>
  // L1:
  // pop rsi
  // syscall
  // ret
  l=asprintf(&b,"j\1X\xbazokaj\1_耀ok%s^\xf\5Ã",v[1]);
  for(b[1]=b[3]=l-21;i*4<l;b++){
    P"mai");
    for(x=++i;x--P"n"))
    P"=");
    for(x='B:5\xc7';*b P"+%d",x),*b-=x)
      for(;*b<x;x/=10)
    P";");
  }
}
\$\endgroup\$
3
  • 1
    \$\begingroup\$ Nice solution. You posted the correct score, but the wrong character set; it should be a=+1;min(){prtf&} (" should be f) \$\endgroup\$ Commented Nov 18, 2023 at 22:45
  • 1
    \$\begingroup\$ Fail %d which results \$\endgroup\$
    – l4m2
    Commented Nov 19, 2023 at 6:50
  • 1
    \$\begingroup\$ 1 is unnecessary \$\endgroup\$
    – l4m2
    Commented Nov 24, 2023 at 8:27
1
\$\begingroup\$

Rattle, 23 bytes, score 3

|II^P[gn[b"+"]`b",=">]`

Try it Online!

The input cannot contain +,= characters.

This generates Rattle code that uses + to increment from 0 to the ASCII value of each character before printing the ASCII character with , and resetting the counter with =. The new code therefore only uses the characters +,= for a score of 3.

Explanation

|                     get input
 I                    save input characters to consecutive memory slots
  I^                  get length of input
    P                 set pointer to 0
     [...]`           repeat N times (N = input length)
     
g                     get the character at the pointer
 n                    get the ASCII value of this character
  [....]`             repeat M times (M = ASCII value of the character)
   b"+"               add "+" to the print buffer
         b",="        add ",=" to the print buffer
              >       move pointer right

This generates code of the form ++++++++++,=++++++++,=++++,= (where there are lots more + depending on the ASCII value of the input characters).

\$\endgroup\$
1
\$\begingroup\$

YASEPL, 24 bytes / score 2

=b$34»=a'#hashtag!~!a~!~

the restricted char set being #". YASEPL is not capable of template strings

\$\endgroup\$
1
\$\begingroup\$

Japt -P, 25 17 bytes, score 1

Ô£"»{'ÄpXc}¹d¹ã½Ñ

Try it

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

Perl 5, 76 bytes, score 7

Input cannot contain &eqs{}~.

print qq!s{}{~qq{@{[~"say	q{@{[<>]}}"]}}}e&&&{~qq{@{[~'CORE::evalbytes']}}}!

Try it online!

Explanation

Uses unary stringwise-negation so all chars from the input string are represented using their binary inverse (e.g. char 0b01000001 - 65, A - becomes 0b10111110 - 190, char depends on charset). The string (including some payload to output say\tq{...}) is stored in $_ using s{}{...}e and is called using &{...} where the method to be called (CORE::evalbytes) is also bitflipped using ~.

\$\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.