22
\$\begingroup\$

Typically, polyglots are constructed in such a manner that each language can ignore parts of the code that are present for other languages, by wrapping them in string literals, using comment syntax, or other similar tricks.

Your goal is to write a polyglot where the output for each language is the code from the polyglot that produces that output. Specifically, the output must be constructed from the polyglot code with only deletions, and it must be a quine in the given language.

Rules

  • Only proper quines are allowed (no reading the source code, no taking input, output must be to STDOUT or closest alternative if STDOUT is not an option, and the programs must consist of more than just literals that are implicitly printed).
  • Since different languages can use different encodings, the raw bytes are what matters here. For example, if language A uses UTF-8 and language B uses CP437, the (hex) code C3 88 46 47 would be ÈFG for language A and ├êFG for language B.
  • All outputs must be distinct (again, comparing raw bytes). This avoids complications with trying to restrict minor language versions - if two languages use the same part of the code to do the same thing, you can't claim them both.
    • If you have two languages A and B such that XY is a valid output in both, but YZ is also valid in B, you may choose XY as the output for A and YZ as the output for B, so you can claim both of them in your score (but you can't claim XY for both languages because of the above rule).
  • All outputs must be as short as possible. For example, if your code was print('foo')#something, for Python 3 (ignoring the fact that the output is not correct), the code you would need to output would be print('foo'), and print('foo')# would not be allowed. If there are multiple strings of equal (minimal) length that produce correct output, you may choose any one of them.
  • Submissions must be polyglots in at least 2 languages.
  • Your score will be given by (number of programming languages with distinct outputs)**3/(total byte size of polyglot). The highest score wins. In the event that two submissions achieve the same score, the submission that reached that score first will win.
\$\endgroup\$
7
  • 2
    \$\begingroup\$ The second to last rule sounds like we need to prove that it's impossible to golf the resulting quine any further by any other possible set of deletions. Is that intentional? \$\endgroup\$ Commented Dec 7, 2016 at 9:14
  • \$\begingroup\$ Related. \$\endgroup\$ Commented Dec 7, 2016 at 9:15
  • \$\begingroup\$ How do you define "deletions" in the case of a language whose commands aren't 8 bits long? Do you delete from the source a command at a time, or a byte at a time? \$\endgroup\$
    – user62131
    Commented Dec 7, 2016 at 14:01
  • \$\begingroup\$ @MartinEnder Good faith can be assumed. Unless someone finds a shorter quine that can be formed from the polyglot, the answer is trusted to be valid. \$\endgroup\$
    – user45941
    Commented Dec 7, 2016 at 17:13
  • \$\begingroup\$ @ais523 Everything is done at the byte level. \$\endgroup\$
    – user45941
    Commented Dec 7, 2016 at 17:13

7 Answers 7

10
+250
\$\begingroup\$

GolfScript + CJam + Fission 2 + Jelly, 4 languages, 24 bytes, score 2.667

Let's start with the hex dump:

00000000:  3322 3024 700a 2721 2b4f 5222 0a3c 3024 700a 6523 7fff cccc

For GolfScript, CJam and Fission 2, we interpret this in some ASCII-compatible single-byte encoding like ISO 8859-1 (the exact encoding doesn't really matter, because the languages only define operators for ASCII characters anyway):

3"0$p
'!+OR"
<0$p
e#<DEL>ÿÌÌ

Where <DEL> is the control character 0x7f.

In Jelly, this is assumed to be in Jelly's own code page, where it looks like this instead:

3"0$p½'!+OR"½<0$p½e#¶”ṘṘ

GolfScript

The e on the last line is an unknown variable and # comments out the remainder of the line, so this prints

"0$p"
0$p

with a trailing linefeed. This is the GolfScript/CJam polyglot version of the standard quine:

".p"
.p

Try the polyglot. | Try the quine.

CJam

Here, e# comments out the last line, so almost identically, this prints

"0$p"
0$p

without a trailing linefeed.

Try the polyglot | Try the quine.

Fission

Fission only sees the second line which is the standard Fission quine, so it prints

'!+OR"

I can't provide an online link for the polyglot here, because TIO sends the file to Fission as UTF-8, but Fission reads the source byte by byte, which makes the last line too long. However, I've tested this locally with an ISO 8859-1 encoded file (in which the last line has the same length as the second), to confirm that this works.

Try the quine.

Jelly

The pilcrow is an alias for linefeeds in Jelly, so the source is equivalent to:

3"0$p½'!+OR"½<0$p½e#
”ṘṘ

All but the last line of a Jelly program are "helper links" (i.e. functions) which can be ignored unless they are called, provided they are syntactically valid. This is actually the reason the 3 comes first in the CJam and GolfScript programs, because otherwise the " can't be parsed in Jelly.

Otherwise, since the function isn't called, the program is equivalent to only its second line, which is the standard Jelly quine.

Try the polyglot. | Try the quine.

\$\endgroup\$
8
\$\begingroup\$

><> + Python, 2 languages, 51 46 bytes, score~=0.16 0.17

Since there are no answers yet, I'll start with a simple one

#.09;!?lo}*2+2f"
_='_=%r;print _%%_';print _%_

Try it for ><> and Python

For ><> the first line is a quine (# reflects, " puts the whole line on the stack, then we push 34 (charcode for ") and print everything) , execution never moves from it, so it effectively ignores the rest of the code.

For Python the first line is a comment, while the second one is a quine (standard approach in python, using string substitution with the same string as both arguments).

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Slight adaptation on the ><> answer can save you some bytes :- #"~r10gol?!;60.| ! \$\endgroup\$ Commented Dec 7, 2016 at 12:00
  • \$\begingroup\$ @Tealpelican Thank you for reminding me the use of .! I adapted my quine using this approach, though I prefer to keep the string in reverse (since this saves bytes) and to avoid using g (since it could be interpreted as "reading the source code") \$\endgroup\$
    – Leo
    Commented Dec 7, 2016 at 14:37
  • \$\begingroup\$ That's a pretty fair point for not using g. Having a look and a little think about it, you can reduce it even further by using the # (ascii 35) from the stack to get your " like; #.09;!?lo}-1" \$\endgroup\$ Commented Dec 7, 2016 at 15:28
6
\$\begingroup\$

JavaScript + Python 2 + Japt, 3 languages, 132 bytes, score ~= 0.205

A="`i96d)p2`i96d)p2";1//2;A=1
S="S=%s;console.log(S,uneval(S))";A//2;S="S=%r;print S%%S";"""
console.log(S,uneval(S))//""";print S%S

This prints

S="S=%s;console.log(S,uneval(S))";console.log(S,uneval(S))

in JavaScript (only in Firefox),

S='S=%r;print S%%S';print S%S

in Python 2, and

`i96d)p2`i96d)p2

in Japt. (Test it online!)

JavaScript

This is what JavaScript sees:

A="`i96d)p2`i96d)p2";1
S="S=%s;console.log(S,uneval(S))";A
console.log(S,uneval(S))

The first line is a no-op because A is not used in any way. The second line sets S to the string S=%s;console.log(S,uneval(S)), and the third prints it after replacing the %s with the unevaled representation of S (just S wrapped in quotes). The result is a quine in JavaScript.

Python

This is basically what Python sees:

A="`i96d)p2`i96d)p2";1//2;A=1
S="S=%s;console.log(S,uneval(S))";A//2;S="S=%r;print S%%S"
print S%S

The first line is pretty much a no-op; the only important part is the A=1 at the end. This turns A into a number so that the integer division A//2 on the second line doesn't throw an error.

The second line is mostly the same way, except it sets S to the string S=%r;print S%%S. The third line prints S after replacing the %r with the raw representation of S (just S wrapped in single-quotes). The result is a quine in Python 2.

Japt

This is the JavaScript code the Japt interpreter sees:

A="`i96d)p2`i96d)p2";1//2;A=1
S="S=%s;console.log(S,uneval(S))";A//2;S="S=%r;print S%%S";"","\nconsole.log(S,uneval(S))//","";.p("r".i("n".t(),S%S))

As you can see, it's mostly the same as the JavaScript answer, with one main exception: the last two lines are combined. As a result, this is what the interpreter actually sees:

A="`i96d)p2`i96d)p2";1
S="S=%s;console.log(S,uneval(S))";A

The first line sets A to the Japt quine, and the second sets S to part of the JS quine. In Japt however, only the last expression is sent to output; this is A, so the output is `i96d)p2`i96d)p2.

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

Jolf + ><>, score = 2**3/15 = 0.533....

"r0:g>o<
"Q«Q«

Working on adding another language to this.

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

><>, Python 2 and 3, 3 languages, 107 bytes, score = 27/107 ~= 0.252

#o<}-1:"
a=1/1is 1;b="(_%(_,b))"[a:-a|9];_='a=1/1is 1;b="(_%%(_,b))"[a:-a|9];_=%r;print %s';print (_%(_,b))

Try it online: Python 2, Python 3, ><>

The Python 3 output is the second line exactly, and the Python 2 output is this quine. The ><> output is the first line.

Explanation

This program is based off of the classic Python 2 quine:

_='_=%r;print _%%_';print _%_

First, to make it compatible with both Python 2 and Python 3, I changed the print statement to a function call, and added an extra space which will come in handy later:

_='_=%r;print (_%%_)';print (_%_)

Next, I needed a way to distinguish Python 2 from Python 3. One of the simplest ways is to take advantage of the fact that / is integer division in Python 2, but float division in Python 3. Thus, the following code evaluates to True in Python 2, but False in Python 3:

1/1is 1

In order to make the outputs distinct between the two languages, I needed to selectively remove the first and last parentheses in the print call (that's why I needed the space earlier - with no space, it wouldn't be a valid print statement in Python 2). Thus, I needed to modify the quine harness like so:

a=1/1is 1;b="(_%(_,b))"[a:-a|9];_='a=1/1is 1;b="(_%%(_,b))"[a:-a|9];_=%r;print %s';print (_%(_,b))

That expression a:-a|9 evaluates to 0:9 in Python 2 and 1:-1 in Python 3. Thus, b is "(_%(_,b))" in Python 3, but in Python 2 the first and last characters are discarded, leaving _%(_,b). And with that modification, the polyglot was valid for this challenge.

As suggested by Teal pelican, the ><> quine #o<}-1:" could be added fairly easily, thanks to the fact that # begins a single-line comment in Python. Simply prepending it and a newline adds another language and increases the score by nearly tenfold.

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

Python 2 + Retina, 2 languages, 55 bytes, score = 2^3/55 ≈ 0.145

I used $n instead of to keep them both valid ASCII.

S='S=%r;print S%%S';print S%S#|
#$n\(*S1`$n\(*S1`
#\`#

Python, Retina

Python:

S='S=%r;print S%%S';print S%S

Retina:


\(*S1`
\(*S1`
\$\endgroup\$
0
\$\begingroup\$

><> + Pyke + Python 2, 81 bytes, score = 3**3/81 ~0.333

"""r00gol?!;60.
a=%r;print a%%a"""#);"34.Cp\D\Es"DEp00/
a=__doc__[-15:]
print a%a

I've tried to do something different with all the languages.

><> sees:

"""r00gol?!;60.

This is a slight modification of the standard ><> quine to use a triple quoted string at the beginning. This allows the ending triple quotes for Python to be on a different line.

Try it online!

Pyke sees:

"34.Cp\D\Es"DEp00/

I hadn't created a quine in Pyke before and thus had to think of one. I used traditional quining techniques to create a string and then eval it with itself as an input. Note for this to work without visual impact, warnings will have to be disabled. Errors out with a division by 0 error in the generation step.

Try it here! Or just the quine part.

Python sees:

It all. Python uses all of the code to produce its quine. I decided to embed the quine part in the docstring (though ultimately it would save bytes to remove but I think it's cool). It's a modification of the standard quining technique.

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.