Python random chain quine

Published on November 18, 2009

Python random chain quine

       Impressed by the Japanese chain polyglot quine given in this habratopike , I, having previously met with quine programs, decided to get to know them more closely. After a quick googling and a brief reading of the wiki / blogs / sites on the topic, my hands were combed and I wanted to write my quine. Quine was written, even in several versions, but this seemed to me not enough. Later I even wrote a double quine (the python code generates the prolog code and the prolog code in turn is the original python code).

       However, a question arose. Is it possible to write a quine of any order (i.e., one that will go into itself after N starts)? As it turned out, this is entirely possible. The result of the research was the following code:

    # xonix
    L=19;B,Q,N,q,n=map(chr,(36,81,78,39,10))
    X='import sys;sys.stdout.write(%s%s%s.replace(chr(36)+chr(81)+chr(36),chr(39)).replace(chr(36)+chr(81),chr(36)).replace(chr(36)+chr(78)+chr(36),chr(10)).replace(chr(36)+chr(78),chr(36)))'
    Y='# xonix%sL=%s;B,Q,N,q,n=map(chr,(36,81,78,39,10))%sX=%s%s%s%sY=%s%s%s%sE="""%s""";exec E%simport sys;sys.stdout.write(b())'
    E="""def b(l=L):
      if l==L: Ql=q
      else: Ql=B+Q*(L-l)+B;Nl=B+N*(L-l)+B
      if l>0: return X%(Ql,b(l-1),Ql)
      else: return Y%(Nl,str(L),Nl,Ql,X,Ql,Nl,Ql,Y,Ql,Nl,E.replace(n,Nl),Nl)""";exec E
    import sys;sys.stdout.write(b())


       The peculiarity of this code is that if you save it to the quine_20_0.py file and then execute the quine_20_0.py and quine_20_20.py files will match binary. Changing L, we can get a cycle of arbitrary length. For those who want to check whether this is so, I can actually provide a verification code:

    python quine_20_0.py > quine_20_1.py
    python quine_20_1.py > quine_20_2.py
    python quine_20_2.py > quine_20_3.py
    ...
    python quine_20_19.py > quine_20_20.py






    # file: quine_n_gen.py
    N = 20 # quine cycle
    Q='''# xonix
    L=${n};B,Q,N,q,n=map(chr,(36,81,78,39,10))
    X='import sys;sys.stdout.write(%s%s%s.replace(chr(36)+chr(81)+chr(36),chr(39)).replace(chr(36)+chr(81),chr(36)).replace(chr(36)+chr(78)+chr(36),chr(10)).replace(chr(36)+chr(78),chr(36)))'
    Y='# xonix%sL=%s;B,Q,N,q,n=map(chr,(36,81,78,39,10))%sX=%s%s%s%sY=%s%s%s%sE="""%s""";exec E%simport sys;sys.stdout.write(b())'
    E="""def b(l=L):
      if l==L: Ql=q
      else: Ql=B+Q*(L-l)+B;Nl=B+N*(L-l)+B
      if l>0: return X%(Ql,b(l-1),Ql)
      else: return Y%(Nl,str(L),Nl,Ql,X,Ql,Nl,Ql,Y,Ql,Nl,E.replace(n,Nl),Nl)""";exec E
    import sys;sys.stdout.write(b())'''.replace('${n}',str(N-1))

    qName = 'quine_%s_0.py' % N
    q = open(qName,'w')
    q.write(Q)
    q.close()

    # test
    import os
    for i in range(N+1):
      os.system('python quine_%s_%s.py > quine_%s_%s.py' % (N,i,N,i+1))
      
    lastQName = 'quine_%s_%s.py' % (N,N)

    print ':)' if open(qName).read()==open(lastQName).read() else ':('

    * This source code was highlighted with Source Code Highlighter.


       This code creates a quine and runs the conversion. If successful (the file at the beginning and at the end matches), the code displays :).

    If it is interesting, I can talk about the process and ideas for creating this quine (as a separate topic).

    UPD . Some explanation of the principle is presented here .