Haskell, 306 + 624 = 930 bytes
Program 1: An anonymous function taking a dummy argument and returning a string.
(\b c()->foldr(\a->map pred)b(show()>>c)`mappend`show(map(map fromEnum)$tail(show c):pure b))"İĴİóđđđÝöÝâÝæÝääē××êääē××İēÀħđĮâħēĕóİóòòĮááħááđéêâéêēááĮÀħ""(\b c()->foldr(\a->map pred)b(show()>>c)`mappend`show(map(map fromEnum)$tail(show c):pure b))"
Try it online!
Program 2: q[[40,...]]
at the end is an anonymous function taking a dummy argument and returning a string.
z~z=[[['@','0'..]!!4..]!!z]
q[x,q]_=z=<<x++q++[34,34]++x
q[[40,92,98,32,99,40,41,45,62,102,111,108,100,114,40,92,97,45,62,109,97,112,32,112,114,101,100,41,98,40,115,104,111,119,40,41,62,62,99,41,96,109,97,112,112,101,110,100,96,115,104,111,119,40,109,97,112,40,109,97,112,32,102,114,111,109,69,110,117,109,41,36,116,97,105,108,40,115,104,111,119,32,99,41,58,112,117,114,101,32,98,41,41,34],[304,308,304,243,273,273,273,221,246,221,226,221,230,221,228,228,275,215,215,234,228,228,275,215,215,304,275,192,295,273,302,226,295,275,277,243,304,243,242,242,302,225,225,295,225,225,273,233,234,226,233,234,275,225,225,302,192,295]]
Try it online!
Character set 1 (includes space):
"$()-:>E\`abcdefhilmnoprstuw×ÝáâäæéêñòóöđēĕħĮİĴ
Character set 2 (includes newline):
!'+,.0123456789<=@[]_qxz~
Since only set 1 contains non-ASCII characters, their UTF-8 bytes are also disjoint.
How it works
Program 1 is generally written with lambda expressions, spaces and parentheses, free use of builtin alphanumeric functions, and with the quine data as string literals at the end.
- Program 1's own core code is turned into string literal data simply by surrounding it with quote marks.
- To support this, every backslash is followed by
a
or b
, which form valid escape sequences that roundtrip through show
.
- Another tiny benefit is that
a
, b
and c
are the only lower case letters whose ASCII codes are less than 100, saving a digit in the numerical encoding used by program 2.
- The string literal encoding of program 2's core code is more obfuscated by using non-ASCII Unicode: Every character has 182 added to its code point to ensure there is no overlap with the original characters.
- 182 used to be 128, until I realized I could abuse the fact that 182 is twice the length of the string literal for program 1's code to shorten the decoding. (As a bonus, program 2 can use newlines.)
Program 2 is generally written with top level function equations (except for the final anonymous one), character literals and decimal numbers, list/range syntax and operators, and with the quine data as a list of lists of Int
s at the end.
- Program 1's core code is encoded as a list of its code points, with a final double quote.
- Program 2's core code is encoded as the list of code points of the string literal used in program 1, still shifted upwards by 182.
Walkthrough, program 1
b
and c
are the values of the string literals for program 2 and 1, respectively, given as final arguments to the lambda expression. ()
is a dummy argument solely to satisfy PPCG's rule that the program should define a function.
foldr(\a->map pred)b(show()>>c)
decodes the string b
to the core code of program 2 by applying map pred
to it a number of times equal to the length of show()>>c == c++c
, or 182
.
tail(show c)
converts the string c
to the core code of program 1, with a final double quote appended.
:pure b
combines this in a list with the string b
.
map(map fromEnum)$
converts the strings to lists of code points.
`mappend`show(...)
serializes the resulting list of lists and finally appends it to the core code of program 2.
Walkthrough, program 2
- The toplevel
z~z=[[['@','0'..]!!4..]!!z]
is a function converting code points back to characters (necessary to write since not all the characters in toEnum
are available.)
- Its code point argument is also called
z
. The laziness marker ~
has no effect in this position but avoids a space character.
['@','0'..]
is a backwards stepping list range starting at ASCII code 64, then jumping 16 down each step.
- Applying
!!4
to this gives a \NUL
character.
- Wrapping that in a
[ ..]
range gives a list of all characters, which !!z
indexes.
- The character is finally wrapped in a singleton list. This allows mapping the function
z
over lists using =<<
instead of the unavailable map
and <$>
.
- The toplevel
q[x,q]_=z=<<x++q++[34,34]++x
is a function constructing program 1 from the quine data list.
x
is the data for the core of program 1 (including a final double quote) and the inner q
is the obfuscated data for the core of program 2. _
is another dummy argument solely to make the final anonymous function a function instead of just a string.
x++q++[34,34]++x
concatenates the pieces, including two double quote marks with ASCII code 34.
z=<<
constructs program 1 by mapping z
over the concatenation to convert from code points to characters.
- The final
q[[40,...]]
is an anonymous function combining q
with the quine data.
2Related. – Martin Ender – 2018-01-23T17:22:24.297
1Related, Related. – Post Rock Garf Hunter – 2018-01-23T18:07:06.957
3I would presume that two programs that read one another's source are banned as well. – Giuseppe – 2018-01-23T23:41:34.843
@Giuseppe Yes. – Conor O'Brien – 2018-01-24T00:13:51.660
2I'd love to see a non-esolang answer to this challenge. (I had a bit of a thought about how to do that, but so far I haven't seen a way. It might be possible in Forth though, since it's not case sensitive and doesn't rely much on non-alphabetic characters.) – Nathaniel – 2018-01-24T11:39:49.283
Can I pass the same flag to the interpreter/compiler of both programs? – BlackCap – 2018-01-28T07:31:05.587
@BlackCap please elaborate? – Conor O'Brien – 2018-01-28T07:32:15.847
I don't actually have an answer that uses this, but would something like
bc -not
and the programs0
and1
be an acceptable answer if I pay for the flag? – BlackCap – 2018-01-28T07:37:24.340@BlackCap I still don't quite get your question. Are you asking if you can add different arguments to the two programs? Or are you asking if arguments are allowed? – Conor O'Brien – 2018-01-28T07:39:51.597
1If I can pass the same argument, not to the programs themselves, but to the compiler of both programs. Typically compiler flags are allowed if you pay for them, but for this challenge you might argue it goes against the mutually exclusive rule. – BlackCap – 2018-01-28T07:43:28.260
There is an obvious problem with applying the part of the proper quine definition that says there must be a part of the program that encodes something other than itself. That only makes sense for this kind of variant if you interpret it as "after going a full cycle". But if you do that, then I think @BlackCap's suggestion is disallowed. – Ørjan Johansen – 2018-01-28T10:08:21.750
@BlackCap The rules about flags had been changed last I heard. They now cost nothing but which flags are used is considered part of the language choice. (So you'd need to specify something like "
bc
with-not
flag" as the language.) – Ørjan Johansen – 2018-01-28T10:11:42.480@ØrjanJohansen 's suggestion makes sense. I suppose then if you were to use flags, they must be consistent. – Conor O'Brien – 2018-01-28T16:09:49.827