Ентропічна Квіне!


12

Ваше завдання - написати програму або функцію, яка:

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

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

Наприклад, якщо ваша квітка була ABCD, повторно запущена, вона може надрукувати:

ABCD
A!CD
j!CD
j!CjD

Технічні умови

  • Зміна символу є або:

    • Вставка випадкового символу,
    • Видалення випадкового символу, або
    • Заміна символу новим випадковим символом. Зауважте, що новий символ може бути таким же, як той, який він замінює, і в цьому випадку зміни не будуть здійснені.

    Звичайно, видалення або заміна символу з порожнього рядка не є дійсною зміною.

  • Незважаючи на те, що це позначено , правила щодо читання вихідного коду не застосовуються.

Ви можете використовувати будь-який набір символів, якщо він містить символи, використані у вихідному коді.


1
До яких символів посилається кожен персонаж ?
Денніс

2
Як часто це доводиться працювати? Зрозуміло, що це не може бути довільно часто чи інакше, будь-яка можлива програма, довша чи довша, ніж початкова, повинна бути вирішенням проблеми.
Мартін Ендер

1
Чи можна персонаж додати де-небудь, або просто в кінці?
Conor O'Brien

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__, допоможе і на першому кроці.
Ørjan Johansen

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 randoms до кінця вихідного файлу. Кожен запуск, це буде додаватися до цілого числа, яке кодує всі зміни початкового джерела, які відбулися.

  • 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)) - Друкуйте змінене джерело.


Чи видаляє це іноді неіснуючий символ з кінця рядка? Так як 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.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.