27
\$\begingroup\$

Inspired by Hyperprogramming: N+N, N×N, N^N all in one.
Thanks to @MartinEnder and @trichoplax for their help in the sandbox.

Definitions

Hyperquines

Define a hyperquine of order n as a quine-like full program or function P that satisfies all rules that apply to proper quines and, in addition, has the following structure.

P is the concatenation of character groups that consist of n copies of the same character. When P is executed, the output is the concatenation of the same groups, augmented by one more copy of the character.

Examples

  • In a hypothetical programming language where the source code aabbcc generates the output aaabbbccc, this program constitutes a hyperquine of order 2.

  • The definition does not require the characters of different groups to be different.

    If the source code aabbcc generates the output aaaabbbbcccc, the program is a hyperquine of order 1; the source code consists of six single-character groups, the output of six character pairs.

  • In GS2, the empty program prints \n, and the program \n prints \n\n. However, neither \n nor \n\n are hyperquines, since they they do not satisfy all properties of proper quines; no part of the source code encodes a different part of the output.

Hyperquine chains

Define a hyperquine chain of length n as a finite sequence of n full programs or n functions
(P1, …, Pn) that satisfies the following constraints.

  1. The outputs of P1, …, Pn-1 are P2, …, Pn, respectively.

  2. P1, …, Pn are hyperquines.

  3. The orders of P1, …, Pn form a strictly increasing sequence of adjacent integers.

Finally, define an infinite hyperquine chain as an infinite sequence of full programs or functions (P1, P2, …) such that each initial interval (P1, …, Pn) constitutes a hyperquine chain of length n.

Examples

  • In a hypothetical programming language where the source code aabbcc generates the output aaabbbccc, which, in turn, generates the output aaaabbbbcccc, the pair (aabbcc, aaabbbccc) constitutes a hyperquine chain of length 2.

    Note that aaaabbbbcccc – the output of the last hyperquine in the chain – doesn't have to produce a specific output; it doesn't even have to be valid source code.

  • Continuing the previous example, if aaaabbbbcccc generates the output aaaaabbbbbccccc, the triplet (aabbcc, aaabbbccc, aaaabbbbcccc) constitutes a hyperquine chain of length 3.

    If this pattern continues forever, the sequence (aabbcc, aaabbbccc, aaaabbbbcccc, …) constitutes an infinite hyperquine chain.

  • The pair of programs (abc, aabbcc) with outputs (aabbcc, aaaabbbbcccc) is not a hyperquine chain, since the orders of the hyperquines are both 1, so they do not form a strictly increasing sequence.

  • The pair of programs (aabbcc, aaaabbbbcccc) with outputs (aaaabbbbcccc, aaaaabbbbbccccc) is not a hyperquine chain, since the orders of the hyperquines are 1 and 4, so they do not form a sequence of adjacent integers.

Rules

Task

In a programming language of your choice, write a non-trivial hyperquine chain, i.e., a chain that consists of at least 2 hyperquines.

As usual, your programs may not take any input or access their own source code in any form.

If your interpreter prints an implicit newline, your hyperquines have to account for this.

All standard loopholes – especially those related to quines – apply.

Scoring

The longest hyperquine chain wins. If two or more submissions are tied, the submission among these that starts with the shortest hyperquine (measured in characters) wins. As usual, posting time is the final tiebreaker.


You must use the same character encoding for source code, output, character count, and execution. For example, the Python program print 42 is not a 2-character UTF-32 submission, since the interpreter treats each byte as a single character. If your language of choice is not character-based, treat all individual bytes as characters.

\$\endgroup\$
2
  • 3
    \$\begingroup\$ Okay, so maybe Helka's challenge wasn't impossible, but surely this is :D \$\endgroup\$
    – Beta Decay
    Oct 6, 2016 at 6:12
  • 1
    \$\begingroup\$ @BetaDecay Is it really? :) \$\endgroup\$ Oct 7, 2016 at 8:44

2 Answers 2

10
\$\begingroup\$

Befunge-98, infinite order, 54 52 38 36 bytes

Second approach - infinite order, 36 bytes

This program would actually break at the 34th hyperquine since the ASCII value of " would disrupt the string interpretation (and at 59, ;), but we offset the storage of that value to a position that will never be executed (i.e. (0, 1) instead of (0, 0)).

1+::0*x01pn'!1+:#jr;,kg10@k!:kg10;#"

Try it online: 1, 2, 10, 34, 42

Explanation

INSTRUCTIONS  STACK (PYTHON PSEUDOCODE)           EXPLANATION
1+            [n]                                 Push n many 1s onto the stack, then sum them up
::            [n]*(at least 3)                    Duplicate that sum at least twice
0*            [n]*(at least 2)+[0]                Push a whole lot of zeros, then multiply them all together
x             [n]*(at least 1)                    Pop a vector off the stack (n, 0) and set the IP delta to that; now the IP is only executing every nth character
01p           [n]*(at least 1)                    Place n in the program at coordinates (0, 1); this is just for storage
n             []                                  Clear the stack
'!1+          ['"']                               '!' is character 33; one less than 34, or '"'
:#jr          ['"']                               We duplicate the 34 (all we care is that it's a rather large number), then turn around and skip that many spaces
                                                  The IP, having jumped 34*n instructions to the left, is now way in the negatives
                                                  Execution resumes on the other side of the program (the following instructions have been reversed for readability
"             [the program of order 1]            The quote-at-the-end-of-the-program is a common trick for one-liner Befunge quines
#; ... ;                                          Jumps into a loop (when the IP hits one semicolon it skips to the next, restarting the loop)
01gk:         [(rest of string), char*(n+2)]      This duplicates the letter n+1 times*, leaving n+2 copies on the stack
!k@                                                If the number on the top of the stack is zero (i.e. we are printing), it will execute '@',
                                                  ending the program; otherwise, it will NOT execute '@' and will instead continue normally
                                                  Vague* 'k' instruction FTW
10gk,                                             If we aren't done yet, print the character n+1 times* (and restart the loop)

* 'k' is a very strange instruction. It pops a number off the stack; if the number is zero, it skips the command in front of it. If the number is greater than zero,
  it will execute the instruction that many times PLUS ONE. This is actually strangely advantageous in this program.

First approach - order 34, 52 bytes (uses introspection, so technically not legal)

For the reason in the above post, this program would break at order 34 (though I haven't tested).

1+::0*x:00p'1\k:00gk,1#;:00g*0g00gk:$00gk,1+:'4-!k@;

Try it online!

\$\endgroup\$
3
  • 2
    \$\begingroup\$ While the output appears to be correct and this is certainly impressive, I'm not convinced a proper quine can use g, which seems to directly read the program's source code. That said, I'm hardly a Befunge expert, so I might be misunderstanding something. \$\endgroup\$
    – Dennis
    Oct 7, 2016 at 2:51
  • \$\begingroup\$ I'm using g for two purposes here: to store data and to read the source code. The second one might be a little sketchy, even though esolangs.org/wiki/Befunge#Quine has an example using g to read the source code as well. In the meantime, I'll see if I can create a version that doesn't use any introspection. \$\endgroup\$
    – Hactar
    Oct 7, 2016 at 11:05
  • \$\begingroup\$ I knew this had to be possible in Befunge, but I had no clue how. Thanks for showing me. +1 \$\endgroup\$ Oct 21, 2016 at 12:49
10
\$\begingroup\$

><>, infinite order, 178 bytes

The program contains a trailing linefeed.

^
.
*
&
:
&
+
*
2
b
*
*
6
9
$
0
)
*
4
8
:
~
.
*
&
:
&
+
*
2
b
*
*
2
b
$
0
)
i
:
-
1
o
a
&
:
&
o
~
.
*
&
:
&
+
*
7
7
*
*
4
6
$
0
)
0
:
-
1
$
o
:
$
&
:
&
&
,
*
8
b
-
1
l
}
*
3
d
'

Try it online: 1, 2, 3, 10 (That last one takes a while to run.)

Retina script to generate source from linear program.

Explanation

The main idea is to turn the quine vertical, so that the actual control flow isn't affected by the repetition. E.g. the second hyper quine begins like:

^^

..

**

Since we're only moving through the first column, we don't have to worry about repeated characters. Also when we push the majority of the code as a string with ', this will push a space for each empty line, which gives us a way to determine the number of repetitions. That said, there are some limitations due to these empty lines:

  • We can't use " to push large numbers as character codes in the main part of the quine, because this would push additional 32s which we don't want.
  • We can't use ? or ! because they only skip the next character which would be a space in that case (so they wouldn't actually skip the next command).

Hence, all control flow is done with explicit jumps (2D goto, basically), whose actual offsets we need to calculate based on the number of repetitions.

So let's look at the actual code. We start with ^ so the code is executed bottom up. For easier reading, let's write out the actual code in execution order (and drop the ^ because it's never executed again):

'd3*}l1-b8*,&&:&$:o$1-:0)0$64**77*+&:&*.~o&:&ao1-:i)0$b2**b2*+&:&*.~:84*)0$96**b2*+&:&*.

The ' is the standard quining technique for ><> (and Befunge, I guess). It switches to string mode which means that the encountered characters are pushed onto the stack until the next ' is encountered. Empty lines are implicitly padded with spaces which is why we get all the spaces in between. Empty lines at the end of the program are ignored. So after the IP wraps around and hits the ' again, we've got the first column of the program on the stack, except for the ' itself.

Let's look at how we use this to print the entire program.

d3*}    Put a 36 (the ') at the bottom of the stack. Now the stack holds
        a representation of the entire first column.
l1-     Push the depth of the stack, minus (so minus to ').
b8*,    Divide by 88. The original program has 89 lines. If we divide the 
        depth of the stack (minus 1) by 88, we get the order of the current
        hyperquine (due to all the spaces we've pushed).
&       Store the order of the hyperquine in the register.
        Begin of main loop:
&:&       Push a copy of the register onto the stack. Call that N.
          Begin of line-printing loop:
$:o$        Print a copy of the top character on the stack.
1-          Decrement N.
:0)         Check whether it's still positive (gives 0 or 1).
0$          Put a 0 underneath. This will be the x-coordinate of a jump.
64**        Multiply the conditional by 24. This is the number of commands
            in this inner loop.
77*+        Add this to 49, the offset of the end of the loop.
            The result is line we want to jump to in the order-1 hyperquine.
&:&*        Multiply by the order of the quine (so that we jump further on
            higher quine orders).
.         Jump. If N isn't zero yet, this repeats the inner loop. Otherwise
          we continue right here.
~         Discard N (now 0).
o         Output one last copy of the top character on the stack.
&:&       Push a copy of the register onto the stack. Call that N.
          Begin of linefeed-printing loop:
ao          Print a linefeed.
1-          Decrement N.
:i)         Check whether it's still non-negative (gives 0 or 1).
            The next bit is essentially the same loop structure as above,
            but with loop length 22 and offset 22:
0$
b2**
b2*+
&:&*
.         Jump. If N isn't -1 yet, this repeats the inner loop. Otherwise
          we continue right here.
          Begin of space-clearing loop:
~           Discard the top of the stack. On the first iteration this is the
            -1 from the previous loop. Afterwards, it's one of the spaces
            representing an empty line.
:84*)       Check if the top of the stack is a space.
            And another loop conditional. This one works the other way round:
            the difference is 54, which is the distance between the beginning
            of this loop and the main loop. The offset is the beginning
            of this loop, at 22 as above.
0$
96**
b2*+
&:&*
.         Jump. If the top of the stack is still a space this repeats the 
          inner loop. Otherwise we continue from the top of the main loop.

The program terminates when the stack is empty and the first inner loop fails to print another character.

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