Поради щодо написання лайків


30

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

Яку пораду ви маєте щодо написання належних лайків або програм із властивостями, подібними до квіне? Як завжди, кожна порада повинна відповідати різною.

tips  quine 

Відповіді:


14

Використовуйте evalдля зменшення потреби в копіюванні коду

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

Об'єднання двох примірників означає, що одну інформацію потрібно використовувати для двох цілей. Намагання ставитися до свого коду як до даних часто не представляється можливим, і зазвичай це вважається обманом, коли він є. Однак трактування даних як коду може здійснюватися багатьма мовами за допомогою вбудованого модуля, який зазвичай називається eval. Таким чином, ваша квітина в основному складається з зберігання основного тіла вашої квітки в змінній (щоб ви могли посилатися на неї не один раз), а потім оцінювала цю змінну.

Ось приклад, як це працює (приклад написаний на Python, але щось подібне працює і в багатьох інших мовах):

d='print("d="+repr(d)+"\\neval(d)")'
eval(d)

2
@QPaysTaxes: Я маю на меті зробити свій код тут таким, який можна читати та підтримувати, наскільки дозволяє умова перемоги. На жаль, це все ще зазвичай не відрізняється від шуму ліній ASCII (або просто звичайного шумного рядка, якщо я використовую Jelly) від людей, які не звикли до мови.

14

Скористайтеся форматированием рядків

Один з найпростіших способів створити quine - це визначити рядок, а потім помістити рядок всередину себе за допомогою рядкового форматування.

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

Отже, у цьому прикладі Python quine ми оголошуємо рядок з першою частиною, що дорівнює тому, що знаходиться перед рядком s=, тоді ми дозволяємо вводити рядок з форматуванням %r, і, нарешті, ми ставимо те, що приходить після рядка для його друку та форматування . Новий рядок є тим, що printдрукує зворотний рядок.

Отже, шаблон справді такий, в Python:

<A>'<A>%r<B>'<B>

Щоб розширити існуючу quine за допомогою іншого коду:

<more A>s='<more A>s=%r;print s%%s<more B>';print s%s<more B>

9

Строгі функції

На кількох мовах об'єкти функцій (або еквівалентні конструкції) неявно зберігають свій вихідний код і повертають його при перетворенні в рядок. Це дозволяє компактні лайки без використання рядка eval . Помітним прикладом такої мови є JavaScript:

function f(){console.log(f+"f()")}f()

Цей код визначає та викликає функцію, fяка при виклику друкує власний вихідний код, а потім виклик до себе. Єдина частина програми, яку потрібно дублювати, - це виклик функції f(). Звичайно, орган функції може включати довільну "корисну навантаження" коду, яка також буде виконуватися при виклику функції.


Більш компактна версія цього ж трюку працює на мовах гольфу GolfScript :

{".~"}.~

і CJam :

{"_~"}_~

Кожен з цих лайнів спочатку визначає анонімний блок коду (укладений в дужки), який поводиться як функція об'єкта функції в JavaScript: він може бути виконаний, і якщо він буде закреслений, він повертає вихідний код. Решта коду ( .~в GolfScript або _~CJam) виконує блок, залишаючи його копію в стеці. Код всередині блоку потім висуває рядок на стек, який повторює код поза блоком. Коли перекладач виходить, він автоматично розшифровує та друкує все, що залишилося в стеку. Як і у прикладі JavaScript, ці блоки коду також можуть бути зроблені для перенесення та виконання довільного корисного навантаження додаткового коду без необхідності його дублювання.


9

Використовуйте рядкові роздільники, які гніздяться, не рятуючись

Часто однією з найскладніших частин написання квінти є крок втечі. Це потрібно майже в кожній квінці; проблема полягає в тому, що ви зберігаєте дані якось, і вам потрібно копіювати код, який зберігає дані у висновку quine. Цей код буде містити уникнуту форму даних, тож програма побачить форму, що не змінилася, і вам потрібно буде повторно вийти з неї.

Найпростіший спосіб впоратися з кроком немасштабності полягає в тому випадку, якщо форми, що уникнули і не мають масштабу даних, відрізняються лише наявністю або відсутністю розділових рядків рядків. Таким чином, ухилення - це проста справа додавання нової пари роздільників рядків навколо рядка. На жаль, це однозначно може спрацювати лише в тому випадку, якщо самі роздільники рядків можуть бути виражені в даних без виходу.

Perl - хороший приклад мови, де працює ця хитрість. Хоча звичайними розмежувачами для рядків є "…"або '…', рідше використовуються q(…)гнізда, що дозволяє писати цей тип квітів:

$_=q($_=q(0);s/\d/$_/;print);s/\d/$_/;print

Це код + код даних. s///операція із заміни рядка з регулярними виразками; ми використовуємо 0як маркер і співставляємо його в регулярному виразі як \d("будь-яка цифра"), щоб уникнути використання маркера не один раз (хоча в якості іншої оптимізації ми насправді могли просто використати 0знову, тому що Perl s///замінює лише перше виникнення на за замовчуванням). Зауважте, що тут не потрібен чіткий вихідний крок, оскільки q(…)роздільники можуть бути включені буквально в рядок даних.


8

Коди + дані quines

Найбільш загальна структура для лайки виглядає приблизно як цей псевдокод:

data = " версія, що вийшла з усієї програми,
        при цьому рядок замінено маркером "
program = data.replace (
  вираз, який оцінює маркер, але не згадує його ,
  втік (дані)
програма друку;

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

У цьому є деякі тонкощі. У деяких мовах найважчою частиною виконання цієї операції є написання пропускного коду; багатьма мовами виготовити маркер без зазначення його назви складно; і в деяких езотеричних мовах вам доведеться вигадувати власний різновид літерального рядка. Однак усі три операції, як правило, не викликають особливих проблем.

Наприклад, ми можемо записати Python quine, рятуючись від рядка, використовуючи рядок із repr2 символами послідовності x"(який можна представити як "x\"", тобто не використовувати послідовність x"у поданні рядка самої рядка) як маркер:

d='d=x"\nprint(str.replace(d,"x\\"",repr(d)))'
print(str.replace(d,"x\"",repr(d)))

2
Можливо, варто відзначити (можливо, в іншій відповіді), що вставлення рядка в положення маркера часто є дорогим в esolangs, і, можливо, варто структурувати код таким чином, щоб сама рядок була першою або останньою справою (можливо, відокремлена від кінець одним або двома символами, які ви можете жорстко кодувати), щоб ви знали, куди він повинен піти.
Мартін Ендер

@MartinEnder: Я погоджуюся, що це варто згадати, але це, мабуть, інша відповідь (а не коментар чи редакція у цій відповіді). Більшість порад про квітах - це модифікація цієї загальної структури, тому я хотів спочатку отримати її як підказку, оскільки багато людей не мають уявлення, з чого почати писати лайку.

Альтернативою маркеру є використання двох рядків, я це робив для Glass .
Ørjan Johansen

4

Використовуйте обгортковий вихідний код

На досить небагатьох мовах (в основному двовимірних мовах) вихідний код може обгортатися; за певних обставин (наприклад, у Befunge-98, якщо ваша програма є однолінійним), що пройде повз кінець програми, поверне вас до початку програми. Цей вид нелінійної поведінки означає, що ви можете одночасно писати код, що знаходиться всередині та зовні рядкового літералу; неперевершений "(або будь-який розділовий рядок) ефективно дасть вам рядок, що містить всю решту програми (крім "самої).

Одна з проблем використання цього трюку полягає в тому, що ви отримаєте рядок, як видно з точки зору програми ", а не з початку програми (як хотілося б). Таким чином, найімовірніше, найпростіше переставити програму так, щоб вона "з’явилася на початку або в кінці. Це часто означає подрібнення вашої програми на кілька фрагментів та використання будь-яких цікавих / незвичайних команд управління потоком у вашій мові (більшість мов, які дозволяють рядковим літералам обертатися навколо програми, мають гарний вибір цих).

Хорошим прикладом є @ Justin's Befunge-98 :

<@,+1!',k9"

Незрівняний "в кінці програми обертає всю програму в рядковому літералі, тому (бігаючи праворуч ліворуч через <початок), все, що нам потрібно зробити, - вивести програму ( 9k), потім вивести подвійну лапочку ( '!1+,) та вихід ( @). Для цього економляться дві копії програми (одна як код, одна як дані); дві копії - це той самий фрагмент коду, який просто інтерпретується по-різному.


4

Запам’ятайте будову квіточки

Мені подобається думати про лайків як про три частини, а не про 2:

  • Частина 1: Створення представлення даних частин 2 і 3.
  • Частина 2: Використовуйте дані для алгоритмічного друку назад 1 частини.
  • Частина 3: Розшифруйте подання для друку частин 2 і 3.

Це може полегшити думку про лаври. Ось квітка Python, кожен рядок якої відповідає частині:

s = "print(\"s = \" + repr(s))\nprint(s)"
print("s = " + repr(s))
print(s)

Іноді evalдля видалення дублікатів ви використовуєте або подібне, але, як правило, я виявив, що це допомагає писати прості лайки.

Давайте розглянемо дві різні лайки Underload. Це перше:

(:aSS):aSS

Перша частина полягає у (:aSS)формуванні подання даних. Друге - це те :aS, що друкує (:aSS). Третя частина S, яка друкує :aSS.

Ось друга квітка:

(:aS(:^)S):^

Спочатку це, здається, не підходить. Але якщо розширити quine, ви отримаєте:

(:aS(:^)S):aS(:^)S

Зараз (:aS(:^)S)це частина 1, :aSчастина 2 і (:^)Sчастина 3.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.