Энтропийный Куайн!

12

Ваша задача - написать программу или функцию, которая:

  • При первом запуске выводит исходный код.
  • При последующих выполнениях он должен выводить то, что выводил ранее, но с одним случайным изменением символов (определено ниже). Это не должно быть равномерно случайное изменение, но каждое возможное изменение должно иметь ненулевую вероятность возникновения.

    После первого выполнения ваша программа больше не обязательно будет quine; выходные данные будут изменены (и программа также может изменять себя).

Например, если ваш quine был ABCDзапущен повторно, он может вывести:

ABCD
A!CD
j!CD
j!CjD

Характеристики

  • Изменение персонажа:

    • Вставка случайного символа,
    • Удаление случайного символа или
    • Замена персонажа новым случайным персонажем. Обратите внимание, что новый символ может быть таким же, как тот, который он заменяет, в этом случае никаких изменений не будет.

    Конечно, удаление или замена символа из пустой строки не является допустимым изменением.

  • Несмотря на пометку , правила против чтения вашего исходного кода не применяются.

Вы можете использовать любой набор символов, если он включает символы, используемые в вашем исходном коде.

Esolanging Fruit
источник
1
К каким персонажам относится каждый персонаж ?
Деннис
2
Как часто это должно работать? Очевидно, что это не может быть произвольно часто или иным образом каждая возможная программа дольше или дольше, чем оригинальная должна быть решением проблемы.
Мартин Эндер
1
Может ли персонаж быть добавлен в любом месте, или только в конце?
Конор О'Брайен
1
@ ConorO'Brien Anywhere.
Esolanging Fruit
1
Сколько итераций это должно работать?
Дилнан

Ответы:

7

Python 3 , 288 270 224 212 195 196 194 180 178 168 байт

f=__file__
m=open(f).read()
x=m	
print(end=x)
h=hash
k=h(f)
n=k%2
a=h(m)%-~len(x)
x=x[:a]+(not(k%3)*x)*chr(k%127)+x[a+n:]
open(f,'w').write(m.replace("\t",";x=%r\t"%x))

Попробуйте онлайн!

После печати исходного кода файла на первой итерации мы добавляем дополнительную строку для установки x в новый исходный код, а не m.

Объяснение:

f=__file__    #Open and read the source code
m=open(f).read()

x=m       #Set x to the source code for the first iteration
x="..."
...
x="..."   #Set x to the latest iteration
          #On the last iteration there's a tab character to mark progress
print(end=x)    #Print the previous iteration's text

#Modify the text
h=hash
k=h(f)            #Generate a random number to use
n=k%2             #Whether the character will be inserted or changed/deleted
a=h(m)%-~len(x) #The index of the change
                         #Add 1 to the range to append new characters, and to avoid mod by 0 in the case of an empty string
x=x[:a]+(not(k%3)*x)*chr(k%127)+x[a+n:]    #Make the change

open(f,'w').write(m.replace("\t",";x=%r\t"%x))   #Modify the source code, adding the new iteration of the source code

Предполагая, что hashвозвращается равномерно случайное число, существует вероятность 1/6 вставки нового символа, 1/6 вероятности изменения существующего символа и 2/6 вероятности удаления символа. Каков оставшийся 2/6 шанс, который вы спросите? Почему, это ничего не делает 2/6 времени!

(Вот программа проверки, адаптированная из ответов mbomb007 . Попробуйте онлайн! )

Джо Кинг
источник
Я думаю, f=__file__что поможет на первом этапе тоже.
Орджан Йохансен,
4

Python 3 , 205 195 байт

s='print(end=x);h=hash;k=h(x);n=k%2;a=h(s)%-~len(x);x=x[:a]+(not(k%3)*x)*chr(k%127)+x[a+n:];open(__file__,"w").write("s=%r;x=%r;exec(s)"%(s,x))';x='s=%r;x=%r;x=x%%(s,x);exec(s)';x=x%(s,x);exec(s)

Попробуйте онлайн!

Хотел попробовать версию, которая не читает исходный код. Получилось неплохо, как я и думал, и только 30 или около того байтов за версию, которая делает . Объяснение того, как это работает, в основном совпадает с другим ответом, но инициализирует x по-другому, поскольку не может просто прочитать исходный код.

Джо Кинг
источник
4

Python 2 , 779 801 байт

Хотя задача была отредактирована, чтобы показать, что чтение вашего источника разрешено, я уже создавал свое решение без этого. Итак, чтобы показать, что это возможно, я закончил. Нет чтения исходного файла:

s='s=%r;print s%%s\nfrom random import*;L=4;f=open(__file__,"wa"[L>5]);R=randint\nf.write("\\n".join((s%%s).split("\\n")[1:5:2]).replace("4",`map(ord,s%%s)`))\nif L>5:exec\'b=[];h=%%d\\nwhile~-h:b+=[h%%%%1000];h/=1000\\nwhile b:r,p,n=b[-3:];b=b[:-3];L=[L[:p]+L[p+1:],L[:p]+[r]+L[p+n:]][n<2if L else 1]\\nprint"".join(map(chr,L))\'%%1\n\nn=R(0,2);p=R(0,len(L if L>5else s%%s));r=R(0,255);f.write("%%03d"*3%%(n,p,r))';print s%s
from random import*;L=4;f=open(__file__,"wa"[L>5]);R=randint
f.write("\n".join((s%s).split("\n")[1:5:2]).replace("4",`map(ord,s%s)`))
if L>5:exec'b=[];h=%d\nwhile~-h:b+=[h%%1000];h/=1000\nwhile b:r,p,n=b[-3:];b=b[:-3];L=[L[:p]+L[p+1:],L[:p]+[r]+L[p+n:]][n<2if L else 1]\nprint"".join(map(chr,L))'%1

n=R(0,2);p=R(0,len(L if L>5else s%s));r=R(0,255);f.write("%03d"*3%(n,p,r))


Попробуйте онлайн! (Обратите внимание, что это не изменит источник. Вы должны запустить его локально, чтобы это работало)

Для того, чтобы показать , что преобразования работают, вот тестовая программа ( в настоящее время создано , чтобы всегда выбрать 100для r, и выводит результат для каждой комбинации nи pдля первоначального списка.)



Объяснение:

s='s=%r;print s%%s...';print s%s...

Первая строка - это ваша классическая квинна, но намного длиннее, чтобы учесть, что будет после.

from random import*;L=4;f=open(__file__,"wa"[L>5]);R=randint

Импорт для случайных целых чисел. Lстанет списком ординалов исходного кода, но изначально это целое число, которое не используется нигде в источнике для замены строки. Откройте файл, чтобы написать новый источник. При последующих запусках он откроется для добавления.

f.write("\n".join((s%s).split("\n")[1:5:2]).replace("4",`map(ord,s%s)`))

Удалите первую и третью строки кода. Замените 4вышеприведенное списком порядковых чисел.

if L>5:exec'b=[];h=%d\nwhile~-h:b+=[h%%1000];h/=1000\nwhile b:r,p,n=b[-3:];b=b[:-3];L=[L[:p]+L[p+1:],L[:p]+[r]+L[p+n:]][n<2if L else 1]\nprint"".join(map(chr,L))'%1

n=R(0,2);p=R(0,len(L if L>5else s%s));r=R(0,255);f.write("%03d"*3%(n,p,r))

По кусочкам:

  • if L>5:- пропускает эту строку при первом исполнении. Позже Lбудет список, и это запустится. Я объясню execпоследнее, потому что это не в первый раз.

  • n- случайное число 0-2. Это определяет, какая модификация происходит (0 = вставить, 1 = заменить, 2 = удалить).

  • p - Случайная позиция в списке, в которой произойдет изменение.

  • r - случайное число для вставки или замены в списке

  • f.write("%03d"*3%(n,p,r))- Добавьте 3 ранда в конец исходного файла. При каждом запуске это будет добавление к целому числу, которое кодирует все произошедшие изменения в исходном источнике.

  • exec'b=[];h=%d...'%1...- Получить случайные числа (найденные позже %1при последующих запусках), применить изменения к списку и распечатать.

  • while~-h:b+=[h%%1000];h/=1000- Составьте список рандомов, сгенерированных до сих пор, с учетом лидирующих 1, что предотвращает проблемы с лидирующими нулями.

  • while b:r,p,n=b[-3:];b=b[:-3] - Назначьте случайные числа для этой итерации.

  • L=[L[:p]+L[p+1:],L[:p]+[r]+L[p+n:]][n<2if L else 1] - (0 = вставить, 1 = заменить, 2 = удалить)

  • print"".join(map(chr,L)) - Распечатайте измененный источник.

mbomb007
источник
Это иногда удаляет несуществующий символ в конце строки? Так как pможет быть длина строки. Кроме того, каково поведение с пустой строкой?
Джо Кинг
@JoKing Я добавил тестовую программу. Каждое возможное изменение характера может произойти. Он просто показывает, что каждая позиция может быть выбрана для вставки, замены или удаления, и обрабатывает пустой список. tio.run/##LYoxDsMgDEVnOAUjCAZgRO0NuIHloUOaRIocy6JDT08dpdt/…
mbomb007
Я не думаю, что никакие изменения не действительны, хотя я спросил ОП. Вопрос действительно говоритOf course, deleting or replacing a character from an empty string is not a valid change
Джо Кинг
Я спросил Esolanging Fruit, и они говорят, что никакие изменения не действительны, но не для пустой строки.
Джо Кинг,
1
@JoKing Должно быть исправлено.
mbomb007
1

Java 10, 370 байт

String s;v->{if(s==null){s="String s;v->{if(s==null){s=%c%s%1$c;s=s.format(s,34,s);}else{int r=s.length();r*=Math.random();char c=127;c*=Math.random();s=s.substring(0,r)+(c%%3<2?c:%1$c%1$c)+s.substring(r+(c%%3>0?1:0));}}";s=s.format(s,34,s);}else{int r=s.length();r*=Math.random();char c=127;c*=Math.random();s=s.substring(0,r)+(c%3<2?c:"")+s.substring(r+(c%3>0?1:0));}}

Попробуйте онлайн.

Объяснение:

String s;               // Class-level String variable to store the modifying source code
v->{                    // Method without parameter nor return-type
  if(s==null){          //  If this is the first execution of this function:
    s="String s;v->{if(s==null){s=%c%s%1$c;s=s.format(s,34,s);}else{int r=s.length();r*=Math.random();char c=127;c*=Math.random();s=s.substring(0,r)+(c%%3<2?c:%1$c%1$c)+s.substring(r+(c%%3>0?1:0));}}";
                        //   Set `s` to the unformatted source-code
    s=s.format(s,34,s);}//   And then to the formatted source-code
else{                   //  For any following executions of this function:
  int r=s.length();r*=Math.random();
                        //   Random index in range [0, length_of_modified_source_code)
  char c=127;c*=Math.random();
                        //   Random ASCII character in unicode range [0, 127)
  s=                    //   Replace the current String `s` with:
    s.substring(0,r)    //    The first [0, `r`) characters of the modified source code `s`
    +(c%3<2?            //    If the random option is 0 or 1:
           c:"")        //     Append the random character
        +s.substring(r  //    Append the rest of the modified source code `s`, but:
          +(c%3>0?      //     If the random option is 1 or 2:
             1:0));}}   //      Skip the first character of this second part

Общее объяснение:

-part:

  • Строка sсодержит неформатированный исходный код.
  • %sиспользуется для ввода этой строки в себя с помощью s.format(...).
  • %c, %1$cИ 34используются для форматирования двойных кавычек.
  • ( %%используется для форматирования по модулю %).
  • s.format(s,34,s) складывает все это вместе.

Здесь основная программа Java Quine.

Задача часть:

  • String s; это исходный код, который мы изменим на уровне класса.
  • int r=s.length();r*=Math.random();используется для выбора случайного индекса исходного кода в диапазоне [0, length_of_modified_source_code).
  • char c=127;c*=Math.random();используется для выбора случайного символа ASCII (включая непечатаемые) в диапазоне Unicode [0, 126].
  • c%3используется для выбора случайной опции 0, 1 или 2. Опция 0 добавит случайный символ перед индексом r; опция 1 заменит символ в индексе rслучайным символом; и вариант 2 удалит символ в индексе r.
Кевин Круйссен
источник