13
\$\begingroup\$

This 128-language quine ouroboros (a program which outputs a program in another language, which outputs a program in yet another language, (125 languages later), which outputs the original program) is pretty impressive. But unfortunately, it has a static number of iterations.

Write a program which outputs a program (not necessarily in another language, but it can be), which outputs a program, which outputs a program, etc., which after n iterations, outputs the original program for the first time (i.e. no intermediate program should be the same as the original, because otherwise a quine which ignores its input would work), where n is a non-negative integer provided as input. The input can't be just a number in the original source code (e.g. putting x = <the value of n> at the start of your program), it should be one of the following:

  1. Passed as a command-line argument
  2. Read from standard input
  3. Passed as an argument to a function, which returns/outputs the new program.

For intermediate stages in the ouroboros, your program can either be a fully-functioning program, or a function with no arguments, which, when called, will return/output the next one.

You may not read from the source file itself, or use any quine-like builtins (I don't think there are any which would do this, but there might be)

To be clear, if n = 0, the program should output its own source code.

If n = 1, the program should output a different program, which outputs the original source code.

And so on...

Fewest bytes wins!

Edit:

I should have written "For intermediate stages in the ouroboros, your program can either be a fully-functioning program with no input, or a function with no arguments". If your program outputs the next one in the chain, then waits for input, that's fine, but your program shouldn't need the original value of n.

\$\endgroup\$
6
  • \$\begingroup\$ Related, related. \$\endgroup\$ Commented Jul 3, 2019 at 11:56
  • \$\begingroup\$ Can we 1 index n? So n = 1 means print source code, n = 2 means print code which will print source code etc. \$\endgroup\$ Commented Jul 3, 2019 at 12:46
  • 1
    \$\begingroup\$ Will the iteration versions still have the initial input? So let's say my first input is 3, and I run the program it output. Will there still be an input 3, or no input at all? If there is no input, I guess we need to handle that in case something like getInput() is used without any input provided. Or can we let's say input something random that's unused for later iterations, to prevent errors for the getInput()? A.k.a. is the current Python answer valid? \$\endgroup\$ Commented Jul 3, 2019 at 13:11
  • \$\begingroup\$ I suspect that what we're asked to do is, given an integer n, output a program that is the "initial program" of an ouroboros quine of n iterations, and that our answer shouldn't count as one of the n iterations. Is this correct? \$\endgroup\$ Commented Jul 3, 2019 at 14:12
  • \$\begingroup\$ @KevinCruijssen I probably should have been more clear about that. The intermediate stages can't have input in any form. I guess if the program outputs the next one and then waits for input, that would be fine. \$\endgroup\$
    – pommicket
    Commented Jul 3, 2019 at 22:37

9 Answers 9

5
\$\begingroup\$

05AB1E, 28 bytes

-4 bytes + fix thanks to Kevin Cruijssen

"34çìD«s<©di®ì"34çìD«s<©di®ì

Try it online!


Explanation

This works by appending the remaining number to print to the front of the code, which means it's added to the stack the same way an input would be. In the base case of input of "0" it will not concatenate the 0 on the front.

\$\endgroup\$
2
  • \$\begingroup\$ d is non-negative (>=0) instead of positive (>0). Problem is that to check d without popping it, you need to duplicate it first, but then it also need to be discarded on iteration 0"quinsting", otherwise it will output the duplicated 0. :( \$\endgroup\$ Commented Jul 3, 2019 at 13:36
  • \$\begingroup\$ "34çìD«s<©di®ì"34çìD«s<©di®ì for 28 bytes perhaps (which is still pretty close to your intended approach)? (I'm afraid your current version for iteration 0"34çìD«s<Ddiì"34çìD«s<Ddiì outputs -1 from the Duplicate..) \$\endgroup\$ Commented Jul 3, 2019 at 13:39
4
\$\begingroup\$

Runic Enchantments, 39 bytes

"3X4+kSql1=c*?S:1-}C'LA-}!i:0)2*?~!'´@

Try it online!

Would be 4 bytes shorter than 05AB1E using the same tactic if inputs where less than or equal to 10. But as we need to support arbitrarily large values, it gets more complicated.

Numerical value of n gets placed at the front and parsed as a continuous number literal using ´. "3X4+kSq is the basic quine code. If no value is present at the front, the stack length will only be 1 (the quine) otherwise 2 letting l1=d*? determine how to handle things from there.

  • If there is a value, S:1-}'LA2+-} runs: swap the value to the top, subtract 1, duplicate it, leaving a copy on the bottom of the stack, get the Log10 of that value times 100 (resulting in the value's own character length, plus 1 for the ´), remove that many characters from the end of the string (effectively truncating itself off the end, both where it isn't needed and because it has the wrong value). C is one byte shorter than 2+ and results in the same value.

  • If there is not a value, read one from input.

Regardless: :0)2*? duplicate and compare with zero.

  • If non-zero push ´.

  • If zero, pop the value. We can cheat using ! instead of 2? and save a byte because when ´ tries to execute the first byte it sees is non-numeric and immediately drops out of number mode at the same position.

Print entire stack top to bottom.

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

Java 10, 145 bytes

n->{Long N=n;var s="n->{Long N=%s;var s=%c%s%2$c;return s.format(s,N>0?N-1+%2$cL%2$c:%2$cn%2$c,34,s);}";return s.format(s,N>0?N-1+"L":"n",34,s);}

Try it online and see the outputs of some iterations.

Explanation:

explanation:

  • The var s contains the unformatted source code
  • %s is used to put this String into itself with s.format(...)
  • %c, %1$c, and 34 are used to format the double-quotes
  • s.format(s,34,s) puts it all together

Challenge part:

The first lambda function takes a long input as parameter.

  • This is set in variable Long N=n; in the first iteration. Or in Long N=%s; for next iterations.
  • The ternary check N>0?N-1+"L":"n" will fill this %s with value N-1, appended with L since it's a long and to convert it to a String for the %s, if N is larger than 1. If N is 0 instead (initial input was 0 or this is the last iteration of the interquine-'loop'), it will fill this %s with the initial n instead.
\$\endgroup\$
2
  • \$\begingroup\$ The spec says intermediate outputs have to be a full program or a function without arguments \$\endgroup\$
    – Gymhgy
    Commented Jul 4, 2019 at 4:11
  • \$\begingroup\$ @EmbodimentofIgnorance I know, that's what I have. The first lambda function takes a long function-parameter, and the other lambda functions take an unused Void parameter, which I also always use for challenges stating to take no input because v-> is 1 byte shorter than ()->. \$\endgroup\$ Commented Jul 4, 2019 at 6:48
2
\$\begingroup\$

Haskell, 195 164 bytes

main=putStr(x++show x++"\na=")>>(getLine:cycle[pure$show$a-1])!!a>>=putStr
x="main=putStr(x++show x++\"\\na=\")>>(getLine:cycle[pure$show$a-1])!!a>>=putStr\nx="
a=0

Try it online!

This uses a pretty simple quine technique. We modify it with a variable a which is set to a number. If that number is zero (which it is at the start) we take input and output our source with a set to the input number. If a is not zero we output our source with a set to one less. This way a counts down to zero before outputting the original source.

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

Jelly, 22 20 bytes

“Ṫ_1xẸƲ;Ṿ⁾v,⁾¥ ”v,¥ 

Try it online!

Try repeated calls of code

A full program that takes a single argument \$n\$. Main version outputs correctly to stdout but cannot be used as a function with a function return. The repeated calls version is 2 bytes longer but returns programmatically usable output. L

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

R, 92 bytes

f=function(n=-1){gsub("\\s","",paste("f=",sub("-?\\d+",n-1,paste(deparse(f),collapse=""))))}

Try it online!

If deparse is deemed cheating, here’s an alternative:

R, 108 bytes

function(n=-1){s="function(n=%d){s=%s%s%2$s;sprintf(s,n-1,intToUtf8(34),s)}";sprintf(s,n-1,intToUtf8(34),s)}

Try it online!

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

Python 3.8 (pre-release), 60 56 55 53 bytes

lambda n=-1,s='lambda n=%d,s=%r:s%%(~-n,s)':s%(~-n,s)

Try it online!

-2 bytes thanks to Jo King

As of the 53 byte version, also works in Python 2 and Python 3.

\$\endgroup\$
5
  • \$\begingroup\$ The intermediate function doesn’t seem to be a full program or a function that takes no arguments. \$\endgroup\$ Commented Jul 3, 2019 at 18:31
  • 1
    \$\begingroup\$ That walrus operator := is a welcome addition to Python, that's for sure. \$\endgroup\$
    – mbomb007
    Commented Jul 3, 2019 at 18:40
  • \$\begingroup\$ "For intermediate stages in the ouroboros, your program can either be a fully-functioning program, or a function with no arguments, which, when called, will return/output the next one." \$\endgroup\$
    – mbomb007
    Commented Jul 3, 2019 at 18:41
  • \$\begingroup\$ @NickKennedy Updated to comply with the spec, and coincidentally saved 4 bytes. \$\endgroup\$ Commented Jul 3, 2019 at 19:25
  • 1
    \$\begingroup\$ 53 bytes without using := \$\endgroup\$
    – Jo King
    Commented Jul 4, 2019 at 2:33
1
\$\begingroup\$

Perl 6, 44 bytes

<say '<',S{\d+}=get||0-1,'>~~.EVAL'>~~.EVAL

Try it online!

Takes input via standard input and returns a program where the only thing changed is the first number. Each subsequent program will then output the same program, except with that number decremented.

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

C# (Visual C# Interactive Compiler), 112 bytes

void f(int n=-1){var s="void f(int n={2}){{var s={0}{1}{0};Write(s,(char)34,s,n-1);}}";Write(s,(char)34,s,n-1);}

Saved a lot of bytes thanks to @NickKennedy!

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ The intermediate outputs are neither a full program nor a function that takes a single argument. Also I think you have some ns that should be ls. How about tio.run/##Sy7WTS7O/P@/… \$\endgroup\$ Commented Jul 3, 2019 at 18:57

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.