26
\$\begingroup\$

In this challenge, you'll create some programs which behave similarly to genes. When you run one, it will return one of its two "alleles" (a half of its source code), and concatenating any two alleles from your programs will result in a new, functioning program (which returns its own alleles).

As an example, say you write two programs, \$A\$ and \$B\$. These in turn each consist of two "alleles", \$A_0A_1\$ and \$B_0B_1\$. Running \$A\$ would return either \$A_0\$ or \$A_1\$ randomly, and \$B\$ would return \$B_0\$ or \$B_1\$.

Combining any two of these alleles should form a program \$C\$. For example, \$A_0B_0\$, when run, should return one of \$A_0\$ or \$B_0\$, similarly to its parents. If \$C\$ was instead \$A_1B_0\$, it'd return one of those two alleles instead.

One possibility if you had multiple generations, starting with three programs, could look like this:

There are three initial programs, A, B, and C. Two programs are formed in the next generation, A0C1 and B1C0. These then form a third program (in a third generation), B1C1.

Rules

You must write at least two genetic quines, with each initial one having two unique alleles (the total number of unique alleles should be twice the number of initial programs). All permutations of alleles must form a functioning genetic quine.

A genetic quine takes no input when run, and returns the source code of one of its two alleles, randomly. It consists only of the code in its two alleles, concatenated. For example, if print(xyz) and if 1 were two alleles, print(xyz)if 1 and if 1print(xyz) should both work.

Note that standard quine rules must be followed, so the genetic quines should not read their own source code, and alleles should be non-empty.

The random choice must have a uniform probability of choosing either quine, and the quines must follow standard rules (so non-empty). You may not use the current time (directly) or some undefined behavior for randomness; a properly seeded PRNG or source of randomness should be used.

Scoring

Your score (lowest score per language wins) will be the average byte count of all of your alleles, plus an amount determined by \$\frac{b}{2^{n-1}}\$ (making your total score \$b+\frac{b}{2^{n-1}}\$), where \$b\$ is your average byte count and \$n\$ is the number of genetic quines you wrote. This means that writing two initial programs with four alleles would give you a "bonus" (more like a penalty) of \$\frac{1}{2}\$, three would give you \$\frac{1}{4}\$, four would be \$\frac{1}{8}\$, and so on. This is a penalty, not a multiplier: your score will never be lower than your average byte count.

\$\endgroup\$
8
  • \$\begingroup\$ Can an allele by empty? \$\endgroup\$ Commented Oct 26, 2021 at 3:06
  • 2
    \$\begingroup\$ @RedwolfPrograms "standard quine rules" would surely proclude reading your own source code, which several existing answers do. So is reading your source code actually allowed? \$\endgroup\$
    – pxeger
    Commented Oct 26, 2021 at 8:56
  • 1
    \$\begingroup\$ @pxeger I don't think any of the submissions read their own source code (except yours) \$\endgroup\$
    – Jo King
    Commented Oct 26, 2021 at 10:36
  • 1
    \$\begingroup\$ @JoKing user's JS answer does. (so admittedly, not several, but still...) \$\endgroup\$
    – pxeger
    Commented Oct 26, 2021 at 10:37
  • 1
    \$\begingroup\$ Huh, I thought that stringifying functions was okay, but the consensus seems to be leaning towards it's cheating \$\endgroup\$
    – Jo King
    Commented Oct 26, 2021 at 10:54

8 Answers 8

15
\$\begingroup\$

Haskell + System.Random*, score ~120 bytes.

I've built a way to make an arbitrary number of alleles which grow in length at a rate of \$O(\log(n))\$ So you can add as many of them as you want to the bonus to asymptotically approach 0. I would have to do a lot of math to figure out what the exact optimum number of alleles is, but I can do at least 52.

For the smallest 52:

The following is the base allele:

;main=randomRIO(0,1)>>=([putStr x>>print x,main]!!)where x=";main=randomRIO(0,1)>>=([putStr x>>print x,main]!!)where x="

To get other alleles:

  • Replace all the xs with any letter of the alphabet.
  • Optionally replace both instances of [putStr x>>print x,main] with [main,putStr x>>print x].

You can use longer names too to get as many alleles as you want.

Try it online!

Each allele is also a quine on it's own, which is fun!

But even more fun, you can also concat as many alleles as you want together and it will output one of the given alleles randomly. Unfortunately later alleles will be less likely than earlier alleles if you do more than 2.


* Since it's basically impossible to import stuff properly with the allele stuff going on I take the import via command line flag.

\$\endgroup\$
14
+200
\$\begingroup\$

Lost -A, score 249 \$66+\frac{66}{2^{1404}}\$ = ~66

Starting with Jo King's 66 byte Lost quine:

:2+52*95*2+>::1?:[:[[[[@^%?>([ "
////////////////////////////////

There are several ways of making non-functional tweaks to this code that make it still a quine. In this answer, I'm focusing on the numeric operations. For example, you can change 52* to 19+,28+,37+,46+,55+,5:+,64+,73+,82+,91+,or 25*. This totals 12 different possibilities.

Another set of tweaks is in the operation 95*2+. You can swap the order of operations of the multiplication (59*2+) or the addition (295*+), or rewrite the entire expression as 85*7+ or 76*5+. All of these things are independent of each other, so there are 3*2*2 = 12 ways of writing the same expression. You can also (thanks to Jo King in the comments for pointing this out), write it as :4*7+. Because this depends on the stack before the instruction is executed, it can't be combined with any other permuters, so only adds one more way of writing the expression, bringing the total to 13.

A third set of tweaks (also thanks to Jo King in the comments) is that the 1 can be changed to to 2,3,4,5,6,7,8, or 9, making 9 possibilities. Likewise, the 1? sequence can be moved one space to the left, making a total of 9*2=18 possibilities.

I'm sure someone more familiar with the language than me could write even more of these trivial tweaks.

The tweaks shown there are independent of each other, so you can multiply the 12 ways of writing the first expression by the 13 ways of writing the second expression and the 18 ways of writing the third expression to get 2808 unique quines. If a Lost program consists of two of these quines concatenated together, then Lost's built-in random placement of the IP will result in the program executing one of the quines at random (and thus producing its source code). Each quine, by itself, makes a valid allele, and thus combining two of them produces a genetic quine, resulting in a total of 1404 valid genetic quines.

Similarly to the Haskell answer, you can concatenate any number of alleles together rather than just two, and one of them will be chosen uniformly randomly.

As an example, one could consider program A to be:

:2+52*295*+>::1?:[:[[[[@^%?>([ "
////////////////////////////////
:2+25*295*+>::1?:[:[[[[@^%?>([ "
////////////////////////////////

Try it online!

and Program B to be:

:2+52*259*+>::1?:[:[[[[@^%?>([ "
////////////////////////////////
:2+25*259*+>::1?:[:[[[[@^%?>([ "
////////////////////////////////

Try it online!

\$\endgroup\$
0
4
\$\begingroup\$

Python 3, 81 base allele : 71 bytes, score ~= 71

a=r";from random import*;print('a=r\"'+a[:-8]+'%r))'%choice(a[-7]+'A'))
a=r";from random import*;print('a=r\"'+a[:-8]+'%r))'%choice(a[-7]+'A'))a=r";from random import*;print('a=r\"'+a[:-8]+'%r))'%choice(a[-7]+'B'))

Try it online!

Other alleles can be created by replacing the char A by (almost) any char (except simple quote ', double quote ", backslash \, newline, line feed, tabulation, and null char)

Old solution : Python 3.8 (pre-release), base allele : 81 bytes, score ~= 81

Base allele

exec(_:="A,a,*id=id or print('exec(_:=%r)'%choice([a,_])),_;from random import*")

Try it online!

Other alleles can be created by replacing the first char of the string (here A) by any char which can be used as variable name (except _)

How it works:

I started from the quine exec(_:="print('exec(_:=%r)'%_)")

  • Since id is a python built-in, it is evaluated as True. So id or print(...) won't do anything in the first allele.
  • A,a,*id= ...,_ assigns A to something, a to the string of the current allele and id to []

When come the second allele, id is no evaluated as False and a store the first allele.

  • id or print(...) will now print the quine

  • choice([a,_]) will either be a (the first allele) or _ (the current allele) 'exec(_:=%r)'%choice([a,_]) equals the full code of either one of the allele

\$\endgroup\$
4
\$\begingroup\$

Python 3.8, score ~ 105 104 98 97 95

Base allele:

(lambda A:exec(_:="from random import*;.5>random()!=print('(lambda A:exec(_:=%r))'%_)or A(A)"))

The other alleles can be obtained by replacing all As with lowercase and uppercase alphabets for a total of 52 alleles

Try it online!

Heavily based on the JavaScript answer

-6 thanks to @Jo King

-2 thanks to @Jakque

\$\endgroup\$
5
  • \$\begingroup\$ I think (lambda g:exec(_:="g and __import__('random').random()<.5and g(0)or print('(lambda g:exec(_:=%r))'%_)")) works to save a byte? \$\endgroup\$
    – Neil
    Commented Oct 26, 2021 at 8:26
  • \$\begingroup\$ @Neil, that won't work since the function returns a falsy value causing the final statement to always be executed \$\endgroup\$ Commented Oct 26, 2021 at 8:42
  • 3
    \$\begingroup\$ Instead of checking for g could you just call g(g)? I mean, it'll terminate eventually right? \$\endgroup\$
    – Jo King
    Commented Oct 26, 2021 at 9:02
  • \$\begingroup\$ Oh, I hadn't noticed the extraneous lines in the output. Sorry to disturb you. \$\endgroup\$
    – Neil
    Commented Oct 26, 2021 at 9:14
  • 1
    \$\begingroup\$ -2 bytes Try it online! \$\endgroup\$
    – Jakque
    Commented Nov 3, 2021 at 14:11
2
\$\begingroup\$

Vyxal D, 9 bytes, 10 alleles

single :

`1ȮḢ+"℅qṪ

combined :

`1ȮḢ+"℅qṪ`2ȮḢ+"℅qṪ

Try it Online!

The digit can be replaced by any digit from 0 to 9 for a total of 10 alleles

Explanation

`1ȮḢ+"℅qṪ`         # push `1ȮḢ+"℅qṪ` => [ 1ȮḢ+"℅qṪ ]
          2        # push 2 => [ 1ȮḢ+"℅qṪ , 2 ] 
           Ȯ       # push the second-last item => [ 1ȮḢ+"℅qṪ , 2 , 1ȮḢ+"℅qṪ ]
            Ḣ+     # remove the first char and add  => [ 1ȮḢ+"℅qṪ , 2ȮḢ+"℅qṪ ]
              "℅   # listify and pick at random => [ 1ȮḢ+"℅qṪ ] or [ 2ȮḢ+"℅qṪ ]
                qṪ # quote and remove the last char => [ `1ȮḢ+"℅qṪ ] or [ `2ȮḢ+"℅qṪ ]
                   # implicit output
\$\endgroup\$
1
\$\begingroup\$

Charcoal, 55 bytes per allele, 23 alleles

≔´θ´F´‽´⎚´F´¬´ⅈ´«´´´≔´F´θ´⁺´´´´´κ´θ´»θF‽⎚F¬ⅈ«´≔Fθ⁺´´κθ»

Try it online! Link is to sample program of two alleles. Any of the 22 variables αβγδεζηλμνξπρςστυφχψω can be used in place of θ. (I think it might also be possible to replace the third and sixth s with to double the number of alleles but I haven't tested this. I think I could have also started with the Charcoal quine of the same length from Minimal distinct character quine which would give me a further set of 25 alleles, since that quine doesn't use the ι or κ variables.) Explanation: Mostly based on the Charcoal quine from Golf you a quine for great good!.

≔´θ´F´‽´⎚´F´¬´ⅈ´«´´´≔´F´θ´⁺´´´´´κ´θ´»θ

Assign the string θF‽⎚F¬ⅈ«´≔Fθ⁺´´κθ» (a suffix of the entire allele) to a variable.

F‽⎚

Clear the canvas 50% of the time. (This is only relevant to the second allele, since it's always clear when the first allele runs.)

F¬ⅈ«´≔Fθ⁺´´κθ»

If the canvas is clear, then print a , then print the variable twice, the first time prefixing ´ to each character.

Note that if multiple alleles are concatenated then each has half the chance of the previous allele of appearing except the last allele which has the same chance as the penultimate allele.

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

Ruby, score 66 + 66 / (2 ^ (26*3)) ~ 66

eval$a=%q[($r==false||$r=rand<0.5)&&$><<"eval$a=%q[#$a]\n"&&exit]
eval$b=%q{($r==false||$r=rand<0.5)&&$><<"eval$b=%q{#$b}\n"&&exit}

«Genetic diversity» comes from global variable name («a» - «z») and paired delimiters for %q string notation ((), [] and {}). Non-paired delimiters (as well as ') won't work since they have to be the same inside. And other % notations won't work due to interpolation.

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

Julia 1.0, score ~86

(a=:(push!(ARGS, "$(0 < rand(length(ARGS):1) < print("(a=:($(a)))|>eval;"))")))|>eval;
(b=:(push!(ARGS, "$(rand(length(ARGS):1) > 0 > print("(b=:($(b)))|>eval;"))")))|>eval;

Try it online! (the line break is here only for readability, it should be removed)

4*52=208 alleles, 4 for the different comparison orders and 52 for the variable name ([a-zA-Z]).

Ends with an error, I believe it is allowed (not so sure for quines?)

Based on the following quine, which is explained in this answer by Dennis (adapted for Julia 1.0):
(q=:(print("(q=:($(q)))|>eval")))|>eval Try it online!

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