Радіаційно загартований Квін


39

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

Правила

  • Програма повинна мати принаймні один символ
  • Використовувана мова повинна бути повноцінною (Тож такі мови, як HQ9 +, не підлягають)
  • Усі інші правила, які стосуються звичайних ласощів, також діють тут.
  • Виграє рішення з найменшим вмістом, program_length^(2/n)у якому будь-який набір точно nсимволів може бути видалений під час друку оригінального вихідного коду.

1
Я намагаюся знайти рішення Subleq. Я думаю, що це було б ідеально для такого виклику!


Може, змінити назву, враховуючи, що це не те ж саме, що загартований радіацією квінт? Може бути , «радіаційно доказ Куайн»?
Кіос

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

Рубіновий розчин від відомої "мами". github.com/mame/radiation-hardened-quine
mbomb007

Відповіді:


57

Perl, 1116 1124 байт, n = 3, оцінка = 1124 ^ (2/3) або приблизно 108,1

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

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

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

Програма

Примітка: _безпосередньо перед кожним із чотирьох подій з'являється буквальний символ управління (ASCII 31) -+. Я не думаю, що він копіюється та вставляється на StackOverflow правильно, тому вам доведеться повторно додати його перед запуском програми.

eval+<eval+<eval+<eval+(q(FoPqOlengthFoBBPP181XXVVVVJJJKKKNdoWchopJFtPDevalMODx4KNFrPIPA-MN-TUV-ZPINFsPIFoPqOI.Fo.IQNevalFoINevalIFsPZyI.Fr.IT-UPINsayDFtJqJFsKPZyPT-UFWrYrKD.DEEEEQDx6NsayDNDforB1..4YforB1..4NexitQNevalFo)=~y=A-Z=-+;-AZz-~=r)####>####>####>####>####>####>
;
;
;
;
eval+<eval+<eval+<eval+(q(FoPqOlengthFoBBPP181XXVVVVJJJKKKNdoWchopJFtPDevalMODx4KNFrPIPA-MN-TUV-ZPINFsPIFoPqOI.Fo.IQNevalFoINevalIFsPZyI.Fr.IT-UPINsayDFtJqJFsKPZyPT-UFWrYrKD.DEEEEQDx6NsayDNDforB1..4YforB1..4NexitQNevalFo)=~y=A-Z=-+;-AZz-~=r)####>####>####>####>####>####>
;
;
;
;
eval+<eval+<eval+<eval+(q(FoPqOlengthFoBBPP181XXVVVVJJJKKKNdoWchopJFtPDevalMODx4KNFrPIPA-MN-TUV-ZPINFsPIFoPqOI.Fo.IQNevalFoINevalIFsPZyI.Fr.IT-UPINsayDFtJqJFsKPZyPT-UFWrYrKD.DEEEEQDx6NsayDNDforB1..4YforB1..4NexitQNevalFo)=~y=A-Z=-+;-AZz-~=r)####>####>####>####>####>####>
;
;
;
;
eval+<eval+<eval+<eval+(q(FoPqOlengthFoBBPP181XXVVVVJJJKKKNdoWchopJFtPDevalMODx4KNFrPIPA-MN-TUV-ZPINFsPIFoPqOI.Fo.IQNevalFoINevalIFsPZyI.Fr.IT-UPINsayDFtJqJFsKPZyPT-UFWrYrKD.DEEEEQDx6NsayDNDforB1..4YforB1..4NexitQNevalFo)=~y=A-Z=-+;-AZz-~=r)####>####>####>####>####>####>
;
;
;
;

Пояснення

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

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

Зовнішня обгортка

Зовнішня обгортка - це, як правило, eval<+eval<+eval< ... >####>####...>###(плюс купу крапок з крапками та новими рядками, призначення яких повинно бути досить очевидним; це забезпечити, щоб частини програми залишилися відокремленими незалежно від того, чи буде видалено деякі крапки з комою або нові рядки перед ними ). Це може виглядати досить просто, але це дуже тонко в багатьох напрямках, і тому я вибрав Perl для цього виклику.

Спочатку розглянемо, як функціонує обгортка у непошкодженій копії програми. evalаналізує як вбудовану функцію, яка бере один аргумент. Оскільки очікується аргументація, +тут є одинарний +(який вже буде добре знайомий гольфістам Perl; вони корисні на диво часто). Ми все ще очікуємо на аргумент (ми щойно побачили одинарного оператора), тому <наступне трактується як початок <>оператора (який не приймає аргументів префікса чи постфікса, і, таким чином, може використовуватися в операндному положенні).

<>- досить дивний оператор. Його звичайне призначення - читати файлові файли, і ви розміщуєте ім'я файлових файлів всередині кутових дужок. Крім того, якщо вираз недійсний як ім'я файлового файлу, він робить глобальний (в основному, той самий процес, який оболонки UNIX використовують для перекладу тексту, введеного користувачем, в послідовність аргументів командного рядка; набагато старіші версії Perl фактично використовуються оболонка для цього, але в наш час Perl обробляє глобул всередині). Таким чином, передбачуване використання є таким чином, <*.c>як правило, повертає такий список ("foo.c", "bar.c"). У скалярному контексті (наприклад, аргумент доeval), він просто повертає перший запис, який він виявляє при першому його запуску (еквівалент першого аргументу), і повертає інші записи в гіпотетичних майбутніх запусках, які ніколи не відбудуться.

Тепер оболонки часто обробляють аргументи командного рядка; якщо ви надаєте щось на зразок -rбез аргументів, воно просто передається програмі дослівно, незалежно від того, є файл з таким ім'ям чи ні. Perl діє так само, до тих пір, поки ми гарантуємо, що між символами <та співпаданнями немає символів, які є особливими для оболонки або Perl >, ми можемо ефективно використовувати це, як справді незграбна форма літерального рядка. Ще краще, що парсер для синтаксичних операторів Perl має нав'язливу тенденцію до узгодження дужок навіть у таких контекстах, як це, де це не має сенсу, тому ми можемо <>безпечно гніздоватись (для цього можливо відкриття, необхідне для цієї програми). Основним недоліком усіх цих вкладених <>є те, що уникнути вмісту<>майже неможливо; здається, що два шари не розгортаються з кожним <>, тому, щоб уникнути чогось із внутрішньої сторони всіх трьох, йому потрібно передувати 63 нахилів. Я вирішив, що незважаючи на те, що розмір коду є лише вторинною увагою у цій проблемі, майже напевно не варто було платити такий штраф за мій рахунок, тому я просто вирішив написати решту програми, не використовуючи символів, що ображають.

Отже, що відбувається, якщо частини обгортки видалити?

  • Вилучення у слові evalпризводить до того, що воно перетворюється на голове слово - рядок без значення. Перлу це не подобається, але він трактує їх так, ніби їх оточили цитатами; таким чином eal<+eval<+...трактується як"eal" < +eval<+.... Це не впливає на роботу програми, оскільки в основному це просто отримання результату з сильно вкладених овалів (якими ми все одно не користуємося), закидання його на ціле число та проведення безглуздих порівнянь. (Така річ викликає багато спам-попередження, оскільки це в звичайних обставинах явно не корисно; ми просто використовуємо її для поглинання видалень.) Це змінює кількість потрібних нам дужок кутів закриття (тому що відкриваюча дужка зараз інтерпретується замість цього оператора порівняння), але ланцюжок коментарів наприкінці гарантує, що рядок закінчиться благополучно незалежно від того, скільки разів він вкладений. (Тут є більше #знаків, ніж суворо потрібно; я написав це так, як це робив для того, щоб зробити програму більш стисливою, дозволяючи мені використовувати менше даних для зберігання лайки.)
  • Якщо <видалення видаляється, код тепер розбирається як eval(eval<...>). Вторинне, зовні, evalне має ефекту, тому що програми, які ми оцінюємо, не повертають нічого, що має реальну дію, як програма (якщо вони взагалі повертаються нормально, це звичайно нульовий рядок або барево; частіше вони повертаються через виняток, який змушує evalповернути нульову рядок або використовувати exitдля уникнення повернення взагалі).
  • Якщо +видалення видаляється, це не має негайного ефекту, якщо сусідній код недоторканий; Унарі +не впливає на програму. (Причина оригіналу +полягає в тому, щоб допомогти відновити пошкодження; вони збільшують кількість ситуацій, в яких <інтерпретується як унарний, <>а не як реляційний оператор. Це означає, що для отримання недійсної програми потрібно більше видалення.)

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

eal<evl<eval+<...

і в Perl реляційний оператор <неасоціативний, і, таким чином, ви отримуєте синтаксичну помилку (таку саму, яку ви отримали б 1<2<3). Таким чином, обмеження для написаної програми дорівнює n = 3. Додавання більшої кількості одинарних +видається перспективним способом її збільшення, однак це зробить все більш імовірним, що всередині оболонки може також зламатися, переконавшись, що нова версія програми може бути дуже складною.

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

Всередині обгортки

Код всередині обгортки, по суті, виглядає приблизно так (знову ж таки, існує Control - _що обмін стеками не з’явиться безпосередньо перед цим -+):

eval+(q(...)=~y=A-Z=-+;-AZz-~=r)

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

Ось алфавіт розділових знаків, які стають доступними в результаті глобуса (верхній рядок показує кодування, нижній рядок - символ, який він кодує):

BCDEFGHIJKLMNOPQRSTUVWXYZ
 ! "# $% & '() * +; <=>? @ AZz {|} ~ 

Найбільше, що у нас є купа розділових знаків, які не є глобальними, але корисні при написанні програм Perl разом із символом пробілу. Я також зберегла дві великі літери, буквальну Aта Z(які кодують не собі, а к Tі U, оскільки Aбула потрібна як верхня, так і нижня кінцева точка); це дозволяє нам самостійно писати інструкцію з транслітерації за допомогою нового кодованого набору символів (хоча великі літери не так корисні, вони корисні для визначення змін у великих літерах). Найпомітніші символи, яких у нас немає, є [, \та ], але жоден не потрібен (коли мені знадобився новий рядок у висновку, я створив його за допомогою неявного нового рядка зsayа не потрібно писати \n; chr 10також працював би, але є більш багатослівним).

Як завжди, нам потрібно хвилюватися про те, що станеться, якщо внутрішня частина обгортки буде пошкоджена за межами прямого рядка. Пошкоджений evalзаважатиме що-небудь працювати; ми з цим добре. Якщо лапки будуть пошкоджені, внутрішня частина рядка не є дійсною Perl, і, таким чином, обгортка застане її (а численні віднімання на рядках означають, що навіть якщо ви можете зробити його дійсним Perl, він би нічого не робив, що прийнятний результат). Пошкодження транслітерації, якщо це не синтаксична помилка, призведе до того, що обчислюється рядок, що оцінюється, як правило, приводить до того, що вона стає синтаксичною помилкою; Я не на 100% впевнений, що не існує випадків, коли це порушується, але я зараз змушую це переконатись, і це має бути досить легко виправити, якщо вони є.

Зашифрована програма

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

$o=q<
  length$o  ==181 || zzzz((()));
  do {
    chop ($t = "eval+<"x4);
    $r = '=-+;-AZz-~=';
    $s = '$o=q<' . $o . '>;eval$o';
    eval '$s=~y' . $r . 'A-Z=';
    say "$t(q($s)=~y=A-Z${r}r)" . "####>"x6;
    say ";" for 1..4
  } for 1..4;
  exit>;
eval $o

Люди, які звикли до лайки, визнають цю загальну структуру. Найважливіша частина знаходиться на початку, де ми перевіряємо, що $ o є непошкодженим; якщо символи були видалені, його довжина не буде відповідати 181, тому ми біжимо , zzzz((()))які, якщо це не помилка синтаксису з - за неузгоджені дужки, буде помилкою часу виконання , навіть якщо ви видалите всі три символи, тому що ні один з zzzz, zzz, zz, і zце функція, і немає ніякого способу запобігти її розбору як функції, окрім видалення (((та викликання помилкової помилки синтаксису. Сама перевірка також не застрахована від пошкоджень; ||може бути пошкоджений в |але змусить zzzz((()))виклик бігти беззастережно; пошкодження змінних чи констант спричинить невідповідність, оскільки ви порівнюєте одну із них 0,180, 179, 178Для рівності деякого підмножини чисел 181; і видалення одного =викличе збій синтаксичного аналізу, а два =- неминуче спричиняє LHS для оцінки цілого числа 0 або нульового рядка, обидва з яких є фальсиєю.

Оновлення : ця перевірка була трохи помилковою у попередній версії програми, тому мені довелося відредагувати її, щоб виправити проблему. Попередня версія виглядала так після декодування:

length$o==179||zzzz((()))

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

lengtho179||zzz((()))

lengtho179, будучи босим словом, є правдою і, таким чином, порушує чек. Я виправив це, додавши додаткові два Bсимволи (які кодують символи пробілу), тобто остання версія quine робить це:

length$o  ==181||zzzz((()))

Тепер неможливо приховати і =знаки, і $знак, не створюючи синтаксичної помилки. (Мені довелося додати два пробіли, а не один, тому що довжина вводить 180буквальний 0символ у джерело, яке може бути зловживане в цьому контексті для цілого числення-порівняння нуля з голословом, яке вдається.) Кінець оновлення

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

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

Сценарій підтвердження

Не дуже симпатично, але розміщувати його тому, що хтось запитав. Я кілька разів запускав це з різними налаштуваннями (як правило, змінюючись $minта $maxперевіряючи наявність різних областей); це був не повністю автоматизований процес. Він має тенденцію припиняти роботу через велике завантаження процесора в інших місцях; коли це сталося, я просто змінив $minперше значення, $xяке не було повністю перевірено, і продовжив запуск сценарію (таким чином гарантуючи, що всі програми в діапазоні перевіряються в підсумку). Я перевіряв лише видалення з першої копії програми, оскільки цілком очевидно, що видалення з інших копій більше не можуть.

use 5.010;
use IPC::Run qw/run/;
undef $/;
my $program = <>;
my $min = 1;
my $max = (length $program) / 4 - 3;
for my $x ($min .. $max) {
    for my $y ($x .. $max) {
        for my $z ($y .. $max) {
            print "$x, $y, $z\n";
            my $p = $program;
            substr $p, $x, 1, "";
            substr $p, $y, 1, "";
            substr $p, $z, 1, "";
            alarm 4;
            run [$^X, '-M5.010'], '<', \$p, '>', \my $out, '2>', \my $err;
            if ($out ne $program) {
                print "Failed deleting at $x, $y, $z\n";
                print "Output: {{{\n$out}}}\n";
                exit;
            }
        }
    }
}

say "All OK!";

3
ОП трохи неоднозначне; але я думав, що оцінка буде (1116 * 1116) / 3.
Грег Мартін

@GregMartin: (1116 * 1116) / 3 - це 415152, тому цей запис все-таки виграє за цих обставин. Однак я не думаю, що ОП може означати це, оскільки це дасть дуже малий стимул, щоб можна було впоратися з видаленням кількох символів. Ця квітка може бути менше половини довжини, якщо вона вам потрібна лише для обробки одного видалення символів; це дасть мені ефективну оцінку ÷ 4, якщо ми інтерпретуємо її так, що перевершить ÷ 3, що я отримую від n = 3, і, таким чином, означає, що менш цікаві n = 1 записи насправді кращі оцінки.

2
Я зробив оцінку яснішою. У будь-якому випадку це абсолютно неймовірно; не думав, що хтось отримає n> 1.
takra

1
Щось про Perl сказано, що простіше написати програму без літер, ніж без пунктуації
Роберт Фрейзер

35

Befunge-98 , 884, n = 14, оцінка ≈ 2.636

f00f00f00f00f00f00f00f00f00f00f00f00f00f00f0xxxxxxxxxxxxxxx"""""""""""""""fffffffffffffff'''''''''''''''000000000000000\\\\\\\\\\\\\\\'''''''''''''''000000000000000\\\\\\\\\\\\\\\'''''''''''''''fffffffffffffff\\\\\\\\\\\\\\\111111111111111---------------:::::::::::::::!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!000000000000000aaaaaaaaaaaaaaa---------------bbbbbbbbbbbbbbb---------------***************jjjjjjjjjjjjjjj$$$$$$$$$$$$$$$'''''''''''''''+++++++++++++++kkkkkkkkkkkkkkk,,,,,,,,,,,,,,,333333333333333kkkkkkkkkkkkkkk$$$$$$$$$$$$$$$000000000000000{{{{{{{{{{{{{{{'''''''''''''''888888888888888uuuuuuuuuuuuuuu'''''''''''''''!!!!!!!!!!!!!!!111111111111111+++++++++++++++'''''''''''''''xxxxxxxxxxxxxxx###############;;;;;;;;;;;;;;;:::::::::::::::!!!!!!!!!!!!!!!kkkkkkkkkkkkkkk@@@@@@@@@@@@@@@dddddddddddddddkkkkkkkkkkkkkkk:::::::::::::::eeeeeeeeeeeeeeekkkkkkkkkkkkkkk,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;

Спробуйте в Інтернеті!

Це працює не лише тоді, коли ви видалите рівно 14 символів, але навіть якщо ви видалите будь-яку кількість до 14 символів.

n = 14може здатися дуже довільним вибором, але застосовувана нами техніка може насправді застосовуватися лише для замовлень на радіаційне загартування від 1 до 14, але не дуже легко (можливо, це можливо, але я не маю поняття, як). Квітка порядку 1 становить лише 73 байти (хоча тут використовуються деякі прийоми з гольфу, які не застосовуються до більших n):

200 20 xx""''ÈÈ..aa22**..33kk$$00{{''!!uu''!!11++''xx##;;::!!kk@@::,,,,;;

Пояснення

Коли я працював над цією відповіддю, я виявив, що можна встановити дельту вказівника інструкції в умовах, захищених від (2,0)радіації, за допомогою наступного фрагмента:

20020xx

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

n = 14;
m = 4;
Print @ FromDigits @ {
      m + 1, 0, 
      ## & @@ ((m + 1) IntegerDigits[#, 2, n - 4]),
      m + 1, 0
} & /@ Select[
   Range[0, 2^(n - 4) - 1], 
   AllTrue[
     Subsets[{
         m + 1, 0, 
         ## & @@ ((m + 1) IntegerDigits[#, 2, n - 4]),
         m + 1, 0
       }, 
       {n - m, n - 1}
     ] //. {a___, _, m + 1} | {a___, 0, _} :> {a}, 
     MatchQ@{___, m + 1, 0}
  ] &
];

Це дуже швидко розкрило закономірність. Щоб отримати відповідний фрагмент, який працює для видалення до nсимволів, ви можете використовувати (m0x){n}m0де mє n+1і xє mабо 0. Отже, всі наступні дії будуть працювати для видалення до двох символів:

30030030
30030330
30330030
30330330

Я впевнений, що це можна довести, але я просто перевірив n, що до 7. Звичайно, це працює лише до тих пір, поки ми можемо представити їх n+1як одну цифру, і найбільша така цифра в Befunge 98 - fце 15. Щодо цього мій підхід обмежений n = 14. Якщо хтось знайде спосіб надійно встановити дельту на більшу n+1, ймовірно, можна буде збільшити порядок цієї загартованої на радіацію квіта безстроково.

Давайте розглянемо власне код. В основному це дві частини. Спочатку ми встановили дельту, (15,0)як я щойно згадував:

f00f00f00f00f00f00f00f00f00f00f00f00f00f00f0xxxxxxxxxxxxxxx

А в решті коду кожна команда повторюється 15 разів і друкує джерело. Якщо ми видалимо повторення, це виглядає приблизно так:

"f'0\'0\'f\1-:!!0a-b-*j$'+k,3k$0{'8u'!1+'x#;:!k@dk:ek,;

Це "стандартна 2D-технологія квинінгу: вона запускає рядовий режим, виштовхує всіх символів (крім себе) на стек і знову завершує рядовий режим після завертання. Це допомагає нам отримати всі кодові пункти другого тайму, але нам не вдасться отримати нічого корисного з першої половини, тому що протягом усього f00f00...f0біту він буде записувати лише два символи (які можуть бути fабо 0залежно від того, які символи буде видалено ). Але оскільки ця частина не складається з символів, які повторюються 15 разів, нам все одно потрібно буде надрукувати її окремо.

Більш зручно, що в немодифікованій квінці довжина струни перед рівнем "є-1 (mod 15) . Це гарантує, що незалежно від того, скільки символів (до 14) ми видалимо, кількість записаних там символів завжди 3 (один xі два з fі 0). Це насправді справедливо для будь-якого порядку випромінювання до 14.

Тепер почнемо з друку f00f00...f0частини:

f'0\'0\'f\1-:!!0a-b-*j$'+k,

f          Push 15, a loop counter.
'0\'0\'f\  Put "00f" underneath the loop counter.
1-         Decrement the loop counter.
:!!        Copy it, and turn it into a 1 if it's positive.
0a-b-      Push -21.
*          Multiply by 0 if the loop counter is zero, or by 1 otherwise.
j          Jump that many steps. If the value was 0, this is a no-op and
           the loop ends. Otherwise, this brings us back after the f.
$          Pop the loop counter (which is now 0).
'+k,       Print the top of the stack 43 times, which gives us all of
           the "f00f00...f0" and leaves one "0" on top of the stack.

Наступний 3k$просто відкидає це0 , а також три символи, на які відштовхується "від початку програми. Стек тепер містить лише символи після того, "як і деякі сміття під оригіналом, f00f00...f0залежно від того, які символи були видалені.

Тепер нам просто потрібно перевернути верхню частину стека (що містить решта символів) і надрукувати кожен з них 15 разів.

0{     Start a new, empty stack. This pushes two zeros onto the original stack.
'8u    Move the top 56 values from the original stack to the new one, which
       is the 54 characters after the " as well as those two zeros. This is
       implemented as pop-push loop, so it reverses the order of those elements.
'!1+   Push a " by incrementing a !.
'x     Push an x. Now we've got all the characters that are repeated 15 times.
#;     Enter a loop. This is a standard technique for Befunge-98: the ; is
       a bit like a comment character, that ignores everything until the next
       ;, but we jump over the first one with #, so that from now on only
       the code inside will be executed (over and over).
  :!     Copy the top of the stack, and compute logical NOT (1 if 0, 0 otherwise).
  k@     Terminate the program that many times (i.e. when the top of the
         stack is zero).
  dk:    Make 14 copies of the top of the stack.
  ek,    Print 15 characters from the top of the stack.
;

І це все. :)


16

JavaScript (ES6), 927 байт, n = 1, оцінка = 859329

Примітка: не використовуйте REPL (наприклад, консоль браузера), щоб запустити це.

Це було написано ще до того, як довжина коду була фактором, тому його ще немає в гольф.

Це було дуже важко і заслуговує ґрунтовного пояснення. Про що я напишу пізніше, після того як я ще трохи вивчу цей виклик!

etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;
setTimeout
`c="function f(){x=String.fromCharCode(96);n=String.fromCharCode(10);q=String.fromCharCode(34);y='etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;'+n;z='setTimeout'+n+x+'c='+q+f+';f();_=1'+q+';if(window._);else if(c.length>339)eval(c)//'+x+'///'+x+n+n;console.log(y+z+z)};f();_=1";if(window._);else if(c.length>339)eval(c)//`///`

setTimeout
`c="function f(){x=String.fromCharCode(96);n=String.fromCharCode(10);q=String.fromCharCode(34);y='etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;'+n;z='setTimeout'+n+x+'c='+q+f+';f();_=1'+q+';if(window._);else if(c.length>339)eval(c)//'+x+'///'+x+n+n;console.log(y+z+z)};f();_=1";if(window._);else if(c.length>339)eval(c)//`///`

зауважте: є зворотний новий рядок

В основному, перший рядок ретельно побудований для перейменування всіх «помилок» setTimeoutна дійсні функції, так що, якщо символ буде видалений з одного з setTimeouts, код не помилиться, і незашифрована версія може працювати. Він також написаний так, що якщо будь-який один символ буде видалений з першого рядка, помилок не буде, а решта коду може працювати без змін.

Другий і третій блоки точно рівнозначні. Якщо один працює до завершення, він встановлює _змінну таким чином, щоб інший знав, що не дублювати quine. Якщо один з цих блоків помиляється, це не впливає на інший блок, оскільки його викликали асинхронно за допомогою setTimeout. Помилка не призведе _до встановлення, тому інший блок буде успішно запитаним. Основний код знаходиться в рядку, який перевіряється на довжину в кожному блоці, щоб переконатися, що не було видалення.

Рядки шаблонів у наступному рядку з деякими коментарями в кінці рядків шаблону захищають код від помилок, якщо видалено одну із зворотних посилань, що утворюють рядок шаблону. Якщо видалений кінець backtick видалено, рядок шаблону закінчується зворотним відбитком у коментарі. Якщо стартовий зворотний вибір видалено, setTimeout оцінюється як непризначена функція (без відключення) і код працює як нормально, без setTimeout. Закінчувальний backtick анулюється іншим коментарем.


Що ти кажеш? Хочете спробувати? Нічого не кажи!

Рекомендується повний режим сторінки.

Ігноруйте поле введення, цей фрагмент не вводить.

Спробуйте видалити будь-який один символ із коду!

Не вірите? Звичайний код все ще буде працювати (але він не встигне ...) Спробуйте щось на кшталт console.log(5)!

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

etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;
setTimeout
`c="function f(){x=String.fromCharCode(96);n=String.fromCharCode(10);q=String.fromCharCode(34);y='etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;'+n;z='setTimeout'+n+x+'c='+q+f+';f();_=1'+q+';if(window._);else if(c.length>339)eval(c)//'+x+'///'+x+n+n;console.log(y+z+z)};f();_=1";if(window._);else if(c.length>339)eval(c)//`///`

setTimeout
`c="function f(){x=String.fromCharCode(96);n=String.fromCharCode(10);q=String.fromCharCode(34);y='etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;'+n;z='setTimeout'+n+x+'c='+q+f+';f();_=1'+q+';if(window._);else if(c.length>339)eval(c)//'+x+'///'+x+n+n;console.log(y+z+z)};f();_=1";if(window._);else if(c.length>339)eval(c)//`///`
<!--                               Try the test suite below!                              --><strong id="bytecount" style="display:inline; font-size:32px; font-family:Helvetica"></strong><strong id="bytediff" style="display:inline; margin-left:10px; font-size:32px; font-family:Helvetica; color:lightgray"></strong><br><br><pre style="margin:0">Code:</pre><textarea id="textbox" style="margin-top:5px; margin-bottom:5px"></textarea><br><pre style="margin:0">Input:</pre><textarea id="inputbox" style="margin-top:5px; margin-bottom:5px"></textarea><br><button id="testbtn">Test!</button><button id="resetbtn">Reset</button><br><p><strong id="origheader" style="font-family:Helvetica; display:none">Original Code Output:</strong><p><div id="origoutput" style="margin-left:15px"></div><p><strong id="newheader" style="font-family:Helvetica; display:none">New Code Output:</strong><p><div id="newoutput" style="margin-left:15px"></div><script type="text/javascript" id="golfsnippet">var bytecount=document.getElementById("bytecount");var bytediff=document.getElementById("bytediff");var textbox=document.getElementById("textbox");var inputbox=document.getElementById("inputbox");var testbtn=document.getElementById("testbtn");var resetbtn=document.getElementById("resetbtn");var origheader=document.getElementById("origheader");var newheader=document.getElementById("newheader");var origoutput=document.getElementById("origoutput");var newoutput=document.getElementById("newoutput");textbox.style.width=inputbox.style.width=window.innerWidth-50+"px";var _originalCode=null;function getOriginalCode(){if(_originalCode!=null)return _originalCode;var allScripts=document.getElementsByTagName("script");for(var i=0;i<allScripts.length;i++){var script=allScripts[i];if(script.id!="golfsnippet"){originalCode=script.textContent.trim();return originalCode}}}function getNewCode(){return textbox.value.trim()}function getInput(){try{var inputText=inputbox.value.trim();var input=eval("["+inputText+"]");return input}catch(e){return null}}function setTextbox(s){textbox.value=s;onTextboxChange()}function setOutput(output,s){output.innerHTML=s}function addOutput(output,data){output.innerHTML='<pre style="background-color:'+(data.type=="err"?"lightcoral":"lightgray")+'">'+escape(data.content)+"</pre>"}function getByteCount(s){return(new Blob([s],{encoding:"UTF-8",type:"text/plain;charset=UTF-8"})).size}function onTextboxChange(){var newLength=getByteCount(getNewCode());var oldLength=getByteCount(getOriginalCode());bytecount.innerHTML=newLength+" bytes";var diff=newLength-oldLength;if(diff>0){bytediff.innerHTML="(+"+diff+")";bytediff.style.color="lightcoral"}else if(diff<0){bytediff.innerHTML="("+diff+")";bytediff.style.color="lightgreen"}else{bytediff.innerHTML="("+diff+")";bytediff.style.color="lightgray"}}function onTestBtn(evt){origheader.style.display="inline";newheader.style.display="inline";setOutput(newoutput,"");setOutput(origoutput,"");var input=getInput();if(input===null){addOutput(origoutput,{type:"err",content:"Input is malformed. Using no input."});addOutput(newoutput,{type:"err",content:"Input is malformed. Using no input."});input=[]}doInterpret(getNewCode(),input,function(data){addOutput(newoutput,data)});doInterpret(getOriginalCode(),input,function(data){addOutput(origoutput,data)});evt.stopPropagation();return false}function onResetBtn(evt){setTextbox(getOriginalCode());origheader.style.display="none";newheader.style.display="none";setOutput(origoutput,"");setOutput(newoutput,"")}function escape(s){return s.toString().replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}window.alert=function(){};window.prompt=function(){};function doInterpret(code,input,cb){var workerCode=interpret.toString()+";function stdout(s){ self.postMessage( {'type': 'out', 'content': s} ); }"+" function stderr(s){ self.postMessage( {'type': 'err', 'content': s} ); }"+" function kill(){ self.close(); }"+" self.addEventListener('message', function(msg){ interpret(msg.data.code, msg.data.input); });";var interpreter=new Worker(URL.createObjectURL(new Blob([workerCode])));interpreter.addEventListener("message",function(msg){cb(msg.data)});interpreter.postMessage({"code":code,"input":input});setTimeout(function(){interpreter.terminate()},1E4)}setTimeout(function(){getOriginalCode();textbox.addEventListener("input",onTextboxChange);testbtn.addEventListener("click",onTestBtn);resetbtn.addEventListener("click",onResetBtn);setTextbox(getOriginalCode())},100);function interpret(code,input){_=undefined;window={};alert=function(s){stdout(s)};window.alert=alert;console.log=alert;prompt=function(s){if(input.length<1)stderr("not enough input");else{var nextInput=input[0];input=input.slice(1);return nextInput.toString()}};window.prompt=prompt;(function(){try{_=undefined;eval(code);if(typeof evalResult=="disabled_function_evaluation"){var callResult=evalResult.apply(this,input);if(typeof callResult!="undefined")stdout(callResult)}}catch(e){stderr(e.message)}})()};</script>

Краще пояснення найближчим часом. Тим часом не соромтесь пінг-мене в чаті @jrich з будь-якими коментарями / питаннями / критикою!


ах добре, ого: |
Пуховик

4
Використовуйте thisзамість window.
Mama Fun Roll

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