Pull to refresh

Цепной квайн произвольного порядка на Python

Reading time 3 min
Views 1.7K
   Впечатленный цепным полиглотным квайном японца, приведенным в этом хабратопике, я, ранее уже встречавшийся с программами-квайнами, решил познакомиться с ними плотнее. После беглого гугления и непродолжительного чтения вики/блогов/сайтов по теме, у меня зачесались руки и захотелось написать свой квайн. Квайн был написан, даже в нескольких вариантах, но этого мне показалось мало. Позже я даже написал двойной квайн (код на python генерирует код на prolog а код на prolog в свою очередь первоначальный python-код).

   Однако, тут возник вопрос. А можно ли написать квайн любого порядка (т.е. тот, который будет переходить сам в себя после N запусков)? Как оказалось, это вполне возможно. Результатом изысканий явился следующий код:

# 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())



   Особенностью этого кода является то, что если сохранить его в файл quine_20_0.py а затем выполнить

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


то файлы quine_20_0.py и quine_20_20.py совпадут бинарно. Меняя L можно получить цикл произвольной длины.

Для желающих проверить так ли это на самом деле могу предоставить проверочный код:

# 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.


   Этот код создает квайн и прогоняет преобразование. В случае успеха (файл в начале и в конце совпадает) код выводит :).

Если будет интересно, могу рассказать о процессе и идеях создания этого квайна (отдельным топиком).

UPD. Некое пояснение принципа представлено тут.
Tags:
Hubs:
+25
Comments 9
Comments Comments 9

Articles