I read the article
"The Relay of 50 Quinas" . Indeed, the man wrote a terrific piece, a colossal work, a true work of art. But judging by the comments, many do not understand how such things are done and believe them to be on the verge of, if not beyond human capabilities, especially a lot of emotions were about esoteric languages ​​(Brainfuck, Unlambda, Whitespace) on the list.
In this article I will try to explain how such quineas are written.
Here is the code on the python that generates the code on the brainfack, which generates the code on the anlambda, which generates the original code on the python:
data = 'def brainfuck(st): return "".join(["+"*ord(c)+".>" for c in st])\ndef unlambda(st): return "`r"+"`"*len(st)+"".join(["."+e for e in st])+"i"\nprint brainfuck(unlambda(\'data = %s\'%`data`+chr(10)+data))' def brainfuck(st): return "".join(["+"*ord(c)+".>" for c in st]) def unlambda(st): return "`r"+"`"*len(st)+"".join(["."+e for e in st])+"i" print brainfuck(unlambda('data = %s'%`data`+chr(10)+data))
')
I tried to make the code as clear as possible, however, just in case, I would go over it line by line.
In the first line, all the following lines in the Python representation are encoded. This line is written last, after all the program code is written, it is encoded.
>>> data = 'def brainfuck(st): return "".join(["+"*ord(c)+".>" for c in st])\ndef unlambda(st): return "`r"+"`"*len(st)+"".join(["."+e for e in st])+"i"\nprint brainfuck(unlambda(\'data = %s\'%`data`+chr(10)+data))' >>> print data def brainfuck(st): return "".join(["+"*ord(c)+".>" for c in st]) def unlambda(st): return "`r"+"`"*len(st)+"".join(["."+e for e in st])+"i" print brainfuck(unlambda('data = %s'%`data`+chr(10)+data))
Accordingly, the entire program text can be represented by the following line:
'data = %s'%`data`+chr(10)+data
The unlambda function receives the text and returns the unlambda program to print it.
The brainfuck function is the same for brainfuck.
Well, respectively
brainfuck(unlambda('data = %s'%`data`+chr(10)+data))
this is a string representing a Brainfuck program, outputting a program to Unlambda, outputting a source program to
Python.
It is easy to add new languages ​​to the chain, a function is written for each language, which receives a line and returns a program in that language that prints this line, then this function is added to the output line, and, accordingly, data is re-evaluated.
UpdateI looked at the discussion in the comments and understood what needs to be explained better.
A quay-like construction (hereinafter, it is only about languages ​​where data and code can be separated) can be divided into two parts:
1) a data segment (important point, this part remains empty until the moment when the code is completed, after that it is encoded).2) code segmentA data segment is a certain cipher that can be decrypted in two ways. As a result of decryption, the first method will produce a string representation of the actual data segment, while deciphering with the second method will result in a string representation of the code segment. Combining the results of these transcripts, we get a string that contains all the source code of the program.
In the example above, this line is -
'data =% s'% `data` + chr (10) + data .
'data =% s'% `data` - decoding giving the data segment,
data - decoding giving the code segment, and
chr (10) - moving the line between them.
And further, after we have this magic line in our hands, we can do whatever we want with it. If we just print it, we get the usual quine:
data = "l = 'data = %s'%`data`+chr(10)+data\nprint l" l = 'data = %s'%`data`+chr(10)+data print l
If we invert, we get a program that prints its text backwards:
data = "l = 'data = %s'%`data`+chr(10)+data\nprint l[-1::-1]" l = 'data = %s'%`data`+chr(10)+data print l[-1::-1]
We can write a program that prints its hexadecimal representation:
data = "l = 'data = %s'%`data`+chr(10)+data\nprint ' '.join([hex(ord(e)) for e in l])" l = 'data = %s'%`data`+chr(10)+data print ' '.join([hex(ord(e)) for e in l])
In general, we can write a program that prints its code after any transformation (well, or a chain of transformations, as in our case). The “cipher” does not have to be an internal Python representation of strings, you can encrypt it, for example, in the form of ascii codes, or in some other way and appropriately change the decryption procedure:
data = [108, 32, 61, 32, 39, 100, 97, 116, 97, 32, 61, 32, 37, 115, 39, 37, 100, 97, 116, 97, 43, 99, 104, 114, 40, 49, 48, 41, 43, 39, 39, 46, 106, 111, 105, 110, 40, 91, 99, 104, 114, 40, 101, 41, 32, 102, 111, 114, 32, 101, 32, 105, 110, 32, 100, 97, 116, 97, 93, 41, 10, 112, 114, 105, 110, 116, 32, 108] l = 'data = %s'%data+chr(10)+''.join([chr(e) for e in data]) print l