Програмування прістінського світу


87

Давайте визначимо незайману програму як програму, яка не має жодних помилок, але буде помилкою, якщо змінити її, видаливши будь-яку суміжну підрядку з N символів, де 1 <= N < program length.

Наприклад, три символьна програма Python 2

`8`

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

8`
``
`8

а також усі програми в результаті видалення підрядків довжиною 2 викликають помилки:

`
`

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

Ваше завдання в цьому завданні - написати найкоротшу можливу непрозору програму, яка не потребує введення, але видає будь-яке з наступних п'яти слів:

world
earth
globe
planet
sphere

Яке слово ви обираєте, повністю залежить від вас. Єдине слово плюс необов'язковий новий рядок слід надрукувати у stdout (або найближчій альтернативі вашій мові). Виграє найкоротша програма в байтах.

Примітки:

  • Потрібна окрема програма, а не функція.
  • Слова чутливі до регістру; виведення Worldабо EARTHзаборонено.
  • Попередження компілятора не вважаються помилками.
  • Підпрограми, що помиляються, можуть приймати дані або давати вихідні дані або робити що-небудь ще, доки вони завжди з часом помиляються.

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

<script src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js'></script><script>function go() { var s = $('#i').val(), e = []; for (var i = 1; i < s.length; i++) { for (var j = 0; j <= s.length - i; j++) { e.push(s.substring(0, j) + s.substring(j + i)); } } $('#o').val(e.join('\n---\n')); }</script>Program:<br><textarea id='i' rows='16' cols='80'>`8`</textarea><br><button onclick='go()' type='button'>Go</button><br><br>Programs that should error: (--- separated)<br><textarea id='o' rows='16' cols='80'></textarea><br>


1
@geokavel Так. Вилов винятку означає, що це більше не помилка.
Захоплення Кальвіна

33
Удвічі більше видалених відповідей, ніж не видалених. Це досягнення!
DLosc

1
Чи може програма читати власний вихідний код?
Шельваку

2
Де можна ознайомитись з невідповідними відповідями "близьких, але без сигар" та їх коментарів?
Ві.

1
@Vi. Отримайте 2000 респ., Щоб ви могли переглядати видалені повідомлення .
ThisSuitIsBlackNot

Відповіді:


46

Залізниця , 24 байти

$'main'    #
 -[world]o/

Я думаю, це працює. І це як коротке, так і читабельне (наскільки йде Rail).

  • Якщо видалена підрядка включає будь-яку частину, яку $'main'ми отримуємо Internal Error: Crash: No 'main' function found.
  • Якщо вилучена підрядка включає в себе #, немає можливості, щоб програма вийшла чисто, тому вона завжди закінчується Crash: No valid move. Я вважаю, що неможливо видалити підрядку таким чином, щоб трек утворював дійсний (нескінченний) цикл.
  • Якщо вилучена підрядка знаходиться перед #, вона буде відключена від кінця колії, тому поїзд вийде з ладу (з тією ж помилкою, що і вище).
  • Якщо вилучена підрядка знаходиться після #, вона також від'єднає #кінець треку (і, можливо, навіть початок треку від точки входу $). Так знову ж помилка.

Що стосується фактичної програми: для кожної програми Rail потрібно мати $'main'(або більш тривалий варіант, але ми тут займаємось гольфом) як пункт входу до функції, а поїзд $відправляється на південний схід. Все, що знаходиться на цьому першому рядку, може бути частиною доріжки, тому вилучення 'main'доріжки:

$          #
 -[world]o/

-І /просто шматки рейки , які ми повинні дозволити поїзду взяти ці 45 ° поворотів.

[world]просуває рядок worldі oдрукує її. #позначає кінець колії - єдиний спосіб безпечно припинити програму Rail.

Цікаво, що таке рішення можливе лише тому, що Rail дозволяє трекам проходити через mainлінію - якби це було неможливо, #було б після першого нового рядка і код завжди можна було б скоротити до

$'main'
 #

яка є дійсною програмою, яка нічого не робить. (Non-символи пробілу між 'і #не впливатиме на це.)

Також досить цікаво: якби я щойно гольфував завдання друку, worldвоно не було б набагато коротшим чи простішим:

$'main'
 -[world]o#

4
Що робити, якщо я видаляю будь-які знаки між [і]?
Мартін Лютке

@ MartinLütke він відключить /від #.
Мартін Ендер

2
@ MartinLütke Ви можете не тільки зняти дужки, оскільки вони не є суміжними.
Захоплення Кальвіна

Що робити, якщо видалити новий рядок між двома рядками?
Ві.

1
@Vi. Це відключає $станцію від початку колії, тому поїзд негайно врізається в рух (Rail очікує, що траса продовжить південний схід $).
Мартін Ендер

43

Funciton ( 186 136 байт в UTF-16)

╔══════════════╗
║19342823075080╟
║88037380718711║
╚══════════════╝

Ця програма друкує "світ".

Більшість підрядів, які ви вилучите з цього, не дозволять йому стати повним вікном, на яке аналізатор буде скаржитися. Єдині можливі видалення, які залишають повне поле:

 ╔══════════════╗
|║19342823075080╟  (remove this whole line)
|║88037380718711║
 ╚══════════════╝
 ╔══════════════╗
 ║|19342823075080╟   ← substring starts at | here
 ║|88037380718711║   ← substring ends at | here
 ╚══════════════╝
... ↕ or anything in between these that removes a whole line’s worth ↕ ...
 ╔══════════════╗
 ║19342823075080|╟   ← substring starts at | here
 ║88037380718711|║   ← substring ends at | here
 ╚══════════════╝
 ╔══════════════╗
|║19342823075080╟
 ║88037380718711║  (both lines entirely)
|╚══════════════╝
 ╔══════════════╗
 ║19342823075080╟
|║88037380718711║  (remove this whole line)
|╚══════════════╝

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

╔══════════════╗
║88037380718711║
╚══════════════╝

Це більше не є дійсною програмою, оскільки аналізатор очікує програму з точно одним результатом:

Помилка: вихідні файли не містять програми (програма повинна мати вихід).

Єдина можливість, яка залишає вихідний з'єднувач, є останньою з вищезазначених, яка залишає це:

╔══════════════╗
║19342823075080╟
╚══════════════╝

Однак це число не кодує дійсну рядок Unicode в езотеричному UTF-21 Funciton. Спробуйте виконати це, ви отримаєте:

Невиправлене виняток: System.ArgumentOutOfRangeException: Дійсне значення UTF32 становить від 0x000000 до 0x10ffff, включно, і не повинно включати сурогатних значень кодових точок (0x00d800 ~ 0x00dfff).

Тому ця програма незаймана.


3
Я відчуваю, що вам пощастило в останньому випадку (не те, що так просто випадково отримати дійсну послідовність Unicode, але все-таки ...)
Esolanging Fruit

34

Visual C ++ - 96 95 байт

#include<iostream>
#define I(a,b)a<<b
int main()I({std::cout,I('w',I('o',I('r',I('l','d';)))))}

Властивості:

  1. Ви не можете видалити будь-яку частину int main()без помилки компіляції.
  2. Ви не можете видалити змінити розширення макросів ВЗАГАЛІ, видалення aна всіх засобів main()не отримує {, прибравши bвзагалі означає , що наша лінія не закінчується в ;, прибравши <засіб std::cout<'w'викликає помилку, і усунення <<причин std::cout'w', 'w''o'і т.д.
  3. Ви не можете видалити параметри з визначення макросу або виклику, єдиними допустимими іменами для цього визначення будуть такі I(a), I(b)які ніколи не збігаються і Iякі поширюються на раніше (; з іншого боку, використовуючи I(,причини <<<<, і ,)скидає напівкрапку (забороняючи будь-які інші помилки).
  4. Ви не можете видалити частину всіх std::coutбез запуску в ведучу <<, і тому не можна видалити будь-який з #include<iostream>початку без помилки компіляції.
  5. Ви не можете видалити будь-яку частину одного символу, ''має помилку з порожнім символом і 'w,т. Д. ... спробуйте перетворити все в один символ.
  6. Ви не можете видалити ліву / праву частину макросу, не залишаючи занадто багато )або (з іншого боку, наприклад, ви не можете робити такі речі I('w',I('r'.

Компілює в Інтернеті за допомогою Visual C ++ .

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

У попередніх версіях застосовувався значно інший підхід, і він виявився не первозданним, тому я зняв ці оцінки.


Підтвердження:

Наступна програма підтвердила, що ця версія є первозданною за допомогою clкомпілятора з Visual C ++ 2010. Хотіла, щоб я пошкодував написати це раніше:

#include <fstream>
#include <iostream>
char *S = "#include<iostream>\n#define I(a,b)a<<b\nint main()I({std::cout,I('w',I('o',I('r',I('l','d';)))))}";
//uncomment to print source code before compile
// #define prints
int main(){
   for(int i=0; i<95; i++)
      for(int j=i; j<95; j++){
         std::fstream fs;
         fs.open ("tmptst.cpp",std::fstream::out);
         for(int k=0; k<95; k++)
         if(k<i || k>j){
            fs << S[k];
            #ifdef prints
               std::cout<<S[k];
            #endif
         }
         fs.close();
         #ifdef prints
            std::cout<<'\n';
         #endif
         //Compile and surpress/pipe all output
         //if it doesn't compile we get a nonzero errorlevel (i.e.true) from system.
         if(!system("cl -nologo tmptst.cpp >x"))
            return 0;
      }
      std::cout<<"PRISTINE!";
}

1
Зауважимо, що, хоча це є незайманим у цьому компіляторі, це не так у всіх компіляторів.
Джошуа

1
Наведіть, будь ласка, приклад ....
Лінус

3
У деяких компіляторах порожня програма C ++ дає програму, яка нічого не робить. Залежно від реалізації iostream, #include <iostream> може також компілювати.
Джошуа

5
@Joshua Мають значення лише підпрограми довжиною 1 або вище, тому не має значення, що робить порожня програма.
ThisSuitIsBlackNot

2
@Comintern, не дуже. Якщо ви не встановите прапорець для запуску виконуваного файлу, /cпараметр автоматично включається і він збирається (як би створюючи бібліотеку, а не програму). Якщо ви /cпоставите прапорець у поле запуску, на якому веб-сайт не включений , ви не отримаєте повідомлення про успіх, і замість цього знайдете природне "ПОСИЛАННЯ: фатальна помилка LNK1561: точка входу повинна бути визначена".
Лінус

32

Пітон 3, 79 33

if 5-open(1,'w').write('world'):a

open(1,'w')відкривається стандартний вихід, потім друкуємо рядок. writeповертає кількість написаних символів. Це використовується для загартовування проти видалення підрядки: Видалення частини рядка призводить до повернення чогось іншого, ніж 5, а 5 мінус цього значення оцінюється як істинне. Але це призводить до того, що if-body буде виконано і aне визначено.

Це засновано на розумному незайманому Куайном Андерс Kaseorg в тут .

Оскільки потрібно перевірити лише одне твердження, це набагато коротше, ніж старе рішення, але також менш загальне.

Старе рішення:

try:
 q="print('world');r=None"
 if exec('e=q')==eval(q[17:]):exec(e)
finally:r

Щоб переконатися, що це дійсно незаймана програма:

w=r'''try:
 q="print('world');r=None"
 if exec('e=q')==eval(q[17:]):exec(e)
finally:r'''
exec(w)
for j in range(1,len(w)):
 for i in range(len(w)+1-j):
  e=w[:i]+w[i+j:]
  try:exec(e,{});print('WORKED',e)
  except:pass

Деякі ключові моменти:

  • Кожен виконаний вислів можна видалити. Перевірка того q, що виконано, вимагає заяви за межами q. Це tryдобре вирішує, вимагаючи принаймні двох тверджень, жодне з яких не можна видалити повністю.
  • Перевірка того, що qвиконано, відбувається шляхом оцінки rв кінці.
  • Перевірка того, що qне було змінено, досягається методом eval(q[17:]), який повинен дати оцінку Noneдля qвиконання.
  • ifСтан трохи складніше , щоб отримати право. Для того, щоб його оцінювали, він має хороший побічний ефект налаштування e, який потрібно встановити r. (Це причина, що я використовував Python 3, exprяк функція творить чудеса для побічних ефектів рівня експресії.)

Хіба не виклик, що жодне видалення не призведе до синтаксичної помилки? Ви ніби провокуєте помилки під час виконання.
Мартін Лютке

5
@ MartinLütke Будь-які помилки є чудовими.
Захоплення Кальвіна

1
Гм, чи не це 79 байт?
Метт

@TheMatt Так? Я просто перерахував їх ще раз, і ти, здається, маєш рацію. Можливо, минуле я рахував нові рядки CRLF ... Як бентежно. Дякую!
Філіпп

25

Хаскелл, 61 рік

x=uncurry(:)
main=putStr$x('w',x('o',x('r',x('l',x('d',[])))))

Будь-який тип помилки в порядку? В такому разі:

Хаскелл, 39

main=putStr$take 5$(++)"world"undefined

Чи працює це, якщо ви видалите одну з букв?
lirtosiast

Під час виконання він вийде з ладу. Тому що це буде намагатися оцінити невизначеним.
Мартін Лютке

Це чудово. Ледача оцінка FTW, виявляється!
DLosc

1
Я хочу, щоб "inits" був у прелюдії :(. Тоді: main = putStr $ inits "world" !! 5 (27 байт)
Мартін Лютке

16

JavaScript, 74 73 35 байт

if((alert(a="world")?x:a)[4]!="d")x

Виявляється, відповідь була набагато простішою, ніж я думав ...

Пояснення

if(
  (
    alert(a="world") // throws a is not defined if '="world"' is removed
        ?x           // throws x is not defined if 'alert' or '(a="world")' is removed
        :a           // throws a is not defined if 'a="world"' or 'a=' is removed
  )
  [4]!="d"           // if "world" is altered fifth character will not be "d"
                     // if 'd' is removed it will compare "world"[4] ("d") with ""
                     // if '[4]' is removed it will compare "world" with "d"
                     // if '(alert(a="world")?x:a)' is removed it will compare [4] with "d"
                     // if '?x:a' is removed [4] on alert result (undefined[4]) will error
                     // if '[4]!="d"' is removed the if will evaluate "world" (true)
                     // if '!', '!="d"' or '(alert...[4]!=' is removed the if will
                     //     evaluate "d" (true)
)x                   // throws x is not defined if reached

// any other combination of removing substrings results in a syntax error

видалити все, окрім a="world", не помиляється
anOKsquirrel

3
@anOKsquirrel Можна видалити лише одну підрядку.
Денніс

4
Я переглянув це на кшталт "Чи можу я видалити це? Ні, ця помилка сталася. Чи може це бути видалено? Ну, я думаю, це призведе до цієї іншої помилки. Ага! Ці символи можна видалити! О, почекайте ..." +1
ETHproductions

if(a="world")["bol"+a[4]]не помиляється.
anOKsquirrel

4
Свята корова, зараз вона вдвічі вражаюча! Бажаю, щоб я міг поставити +1 ще раз ...
ETHproductions

15

Java 8, 301 байт

Тому що на кожне запитання потрібна відповідь на Java.

class C{static{System.out.print(((((w='w')))));System.out.print((((o='o'))));System.out.print(((r='r')));System.out.print((l='l'));System.out.print(d='d');e=(char)((f=1)/((g=8)-C.class.getDeclaredFields()[h=0].getModifiers()));}public static void main(String[]a){}static final char w,o,r,l,d,e,f,g,h;}

Розширено

class C {
    static {
        System.out.print(((((w = 'w')))));
        System.out.print((((o = 'o'))));
        System.out.print(((r = 'r')));
        System.out.print((l = 'l'));
        System.out.print(d = 'd');
        e = (char) ((f = 1) / ((g = 8) - C.class.getDeclaredFields()[h = 0].getModifiers()));
    }

    public static void main(String[] a) { }

    static final char w, o, r, l, d, e, f, g, h;
}

Пояснення

  • public static main(String[]a){} необхідно.
  • Якщо декларації поля видаляються (або робляться нестатичними), перший статичний блок не може їх знайти.
  • Якщо статичний блок видалено (або зробити нестатичним), поля не ініціалізуються.

Найважча частина:

  • Якщо finalключове слово видалено, другий рядок оцінюється 1/(8-8), викликаючи / by zeroвиняток.

Чому ви не можете видалити нутрощі будь-яких заяв про друк?
Нік Хартлі

2
@QPaysTaxes Немає порожнього System.out.print()методу. Є для println(), але не для print(). Отже, якщо ви видалите d='d'його, він би видав The method print(boolean) in the type PrintStream is not applicable for the arguments ()як помилку (А якщо ви видалите, d=він дав би The blank final field d may not have been initializedяк помилку).
Кевін Кройсейсен

15

Funciton , 143 142 136 байт

Оцінка в UTF-8, як зазвичай, оскільки UTF-16 була б на два байти більша (завдяки BOM).

╔══════════╗
║1934282307║╔╗
║5080880373╟╚╝
║80718711  ║
╚══════════╝

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

Але літерали в одному рядку є, як відомо, дорогими, як через збільшення кількості символів, так і через більшу кількість символів, що не належать до ASCII. І його згадка про блок "порожніх коментарів" змусила мене задуматися ...

Тому я придумав це більш ефективне рішення, яке використовує додатковий порожній блок коментарів, який ламається, коли ви намагаєтесь видалити все, що залишило б буквальний блок в такт:

  • Ми не можемо видалити третій рядок, оскільки тоді ми видалимо вихідний з'єднувач.
  • Якщо ми видалимо другий рядок, блок коментарів втрачає верхній край і розривається.

Це залишає два варіанти (дякую Стіву, що вказав на це):

  • Видаліть четвертий рядок. Це залишає обидві скриньки в такті. Однак, коли результуюче ціле число 19342823075080880373декодується, відповідна рядок міститиме кодову точку, 0x18D53Bяка не є дійсним символом Unicode, System.Char.ConvertFromUtf32збивається з ArgumentOutOfRangeException.
  • Видаліть повний рядок, починаючи з правого верхнього кута. Знову ж таки, обидва поля залишаються в такті, але отримане ціле число 508088037380718711містило б дві недійсні кодові точки 0x1B0635і 0x140077веде до того самого винятку.

Зауважте, що навіть без порожнього блоку коментарів видалення другого рядка призведе до недійсної точки коду. Але блок коментарів запобігає тому, що ми беремо рядок всередині другого рядка, щоб отримати ціле число, як, 193428037380718711наприклад, що не призведе до помилки.


Що станеться, якщо ви видалите підрядку, починаючи з символу після вихідного з'єднувача і закінчивши рівно на 1 рядок пізніше? тобто видалення середньої лінії блоку коментарів та лінії, що містить "80718711" в головному блоці, але кути обох ящиків залишаються недоторканими.
Стів

@Steve Я змінив відповідь, щоб висвітлити цю справу. Подивившись трохи більше, це фактично дозволило мені зберегти два символи / шість байтів.
Мартін Ендер

10

Рубі, 36

eval(*[(s="planet")[$>.write(s)^6]])

Ми призначаємо s="planet", а потім записуємо цей рядок в STDOUT. Це повертає кількість написаних символів. Ми вважаємо це з 6, так що якщо буде написано що-небудь, крім 6 символів, отримаємо ненулеве ціле число. Потім ми зрізаємо sцей індекс. Тільки 0-й символ s, "p", є дійсним рядком коду (no-op). Ми передаємо це до eval, використовуючи (*[argument])синтаксис, який еквівалентний лише (argument)тому, що він не дійсний поза викликом методу.

Профільність перевірена програмно на Ruby 1.9.3 та 2.2


Святе гімно. Це дивно.
плескати

Що станеться, якщо ви видалите *?
LegionMammal978

Тоді ви передаєте масив eval замість рядка, який є ArgumentError.
гістократ

9

C #, 128 118 101 байт

Думка про зловживання правилом суміжних підрядків.

Код

class h{static void Main()=>System.Console.Write(new char[1
#if!i
*5]{'w','o','r','l','d'
#endif
});}

Чому це працює?

  1. class hі static void Main()потрібні.
  2. Видалення будь-якого з символів у 'w','o','r','l','d'викликає помилку, оскільки масив char ініціалізується з довжиною 1*5.
  3. Ви не можете видалити вміст у Main () без порушення суміжного правила символів, оскільки частини розділені препрограми. (Дивіться нижче)

До гольфу та розлуки

class h
{
    static void Main() =>
        System.Console.Write(new char[1 * 5]{'w','o','r','l','d'});
}

Перевірено з

https://ideone.com/wEdB54

Редагувати:

  • Збережено кілька байтів, використовуючи #if !xзамість #if x #else.
  • Використовується =>синтаксис func. #if!xзамість #if !x. Кредити @JohnBot.
  • Завдяки =>синтаксису func, додатковий стан попередньої програми можна усунути.

Привіт спіраль! Як ви думаєте, ви могли б пояснити як і чому ваша відповідь працює трохи більше?
isaacg

@isaacg Відредаговано. Доказ, який слід наслідувати.
Helix Quar

Я не можу змусити його працювати без staticна Main.
Джонбот

@Johnbot Так. Потрібно помилково скопіювати. Виправлено.
Helix Quar

Ви можете зберегти характер, зробивши Mainв елемент функції Expression працездатних і 2 більше, видаляючи пропуски перед стану препроцесора: class h{static void Main()=>System.Console.Write(new char[1\n#if!l\n*5]{'w','o','r','l','d'\n#if!o\n});\n#endif\n}\n#endif. Це 115 за моїм рахунком.
Джонбот

9

MATLAB, 37 36 33 байт

feval(@disp,reshape('world',1,5))

Оскільки я не впевнений, чи дозволяють ми також виводити ans = , мені довелося знайти певну обробку, щоб вивести її належним чином. Використання fprintf саме по собі не вийшло, тому що б я ні намагався, просто відмовився помилитися. Використання disp саме по собі не було варіантом, оскільки це займе лише 1 аргумент, і сам аргумент, очевидно, також виконуватиметься без помилок.

Якщо також не включити у вихідний файл ans = , MATLAB можна виконати з 20 байтів :

reshape('world',1,5)

я дійсно повинен дізнатися більше про вбудовані функції (+1) // btw ваша програма набрала 20
Abr001am

2
Це дійсно залежить від того, наскільки суворі правила. Вони заявляють, що слід друкувати лише "world" (+ необов'язковий останній рядок), тож це 33 байти.
slvrbld

Так, ми вважатимемо це 33. Дякую за розуміння :)
Захоплення Кальвіна

9

> <> , 17 байт

e"ooooo7-c0pBhtra

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

Друкує "землю".

Єдиний спосіб, коли ><>програма виходить без помилки, - це виконання ;символу, що є проблемою, оскільки ви можете просто видалити всі символи до цього, так що ;це перший символ, виконаний. Ви можете обійти це, скориставшись pкомандою для зміни програми, яка включатиме ;замість виконання. Видалення будь-якого розділу коду призводить ;до того, що ніколи не створюватимуться помилки через недійсні інструкції B, hі t, стекайте під потоком і нескінченними петлями, завдяки чому в кінцевому рахунку не вистачить пам'яті. Я лише повинен був переконатися, що всі нескінченні петлі продовжують заповнювати стек.

Усі варіанти були протестовані за допомогою цього фрагменту python:

code = 'e"ooooo7-c0pBhtra'
count = {"invalid":0, "underflow":0, "memory":0}
for l in range(1, len(code)):
    for x in range(0, len(code)-l+1):
        print(code[:x] + code[x+l:], "\t\t", end='')
        try:
            interp = Interpreter(code[:x]+code[x+l:])
            for _ in range(0,1000):
                interp.move()
            print(len(interp._stack), "< ", end='')
            interp2 = Interpreter(code[:x]+code[x+l:])
            for _ in range(0,2000):
                interp2.move()
            print(len(interp2._stack))
            count["memory"] += 1
        except Exception as e:
            print(e)
            if str(e) == "pop from empty list": count["underflow"] += 1
            else: count["invalid"] += 1
print(count) 
#don't judge me

доданий (дещо змінена версія) офіційним перекладачем fish.py автором програми <<>. Із 152 можливих підпрограм, 92 помилилися з невірних інструкцій, 18 - з підтікання стека та 42 - з втрати пам’яті.

Кумедні факти, що в першій версії цього e"ooooo6-c0pAhtraбуло пару підпрограм Freak, яким вдалося використовувати команду put, щоб розмістити [стек, замість недійсної інструкції A. Крім того, "земля" - це єдина з фраз, яка буде працювати з цим методом, тому що перша буква eє дійсною інструкцією в ><>. В іншому випадку "команда повинна бути розміщена в передній частині програми, і дійсна підпрограма може бути само "собою.


8

Рубі, 34

eval(*[($>.write("world")-1).chr])

Тут є кілька компонентів:

eval(*[ expr ]) запозичено з відповіді гістократа і є первозданним, тому що перевірка зворотного значення expr є дійсною програмою рубіну, яка не помиляється. method(*arr)- синтаксис рубіну, який викликає methodзначення arrаргументів. Причина, яка тут потрібна, полягає в тому, що вона діє лише як параметри методу, так що якщо evalвона видалена, (*[expr])це помилка синтаксису. Якщо expr буде видалено, evalскаржиться на відсутність аргументів

$>.write("world")-1не можна керувати, за винятком всередині рядка та віднімання. $>.write("world")пише "world" в STDOUT і повертає кількість написаних символів, а потім віднімає 1. Для цього, якщо програма не виправлена, значення буде рівно 4 . Якщо він налаштований (або -1вилучено, або рядок скорочено), він поверне один з -1,0,1,2,3 або 5 . Будь-яке інше керування призводить до помилки синтаксису.

Виклик chrна номер повертає символ, представлений цим номером. Отже, коли викликається результат вищенаведеного прикладу, він помиляється на -1, а повертає односимвольну рядок в іншому випадку.

Я насправді не впевнений, чому це так, але здається, що рубін інтерпретується \x04як символ пробілу, що означає, що вираз є дійсним (порожні рубінові програми нічого не роблять). Однак будь-який з інших символів ( \x00- \x03і \x05) призводить до Invalid char '\x01' in expression. Я знайшов це, просто повторившись над можливою математикою, яку я міг би зробити до поверненого числа. Раніше я використовував

$>.write("planet
")*16

де "планета" плюс новий рядок складали 7 знаків, 16 разів отримували 112 для p, єдина однолітерна функція в рубіні визначена за замовчуванням. Якщо не наводити жодних аргументів, це фактично не-оп


Почесна згадка: $><<"%c"*5%%w(w o r l d)дуже близька, але не незаймана. Видалення "%c"*5%результатів без помилок. Міні-пояснення:

$>є stdout і <<є функцією, яка викликається на ньому. "%c"*5створює рядок формату "%c%c%c%c%c", який потім намагається бути відформатованим ( %) масивом: %w(w o r l d)що є коротшою версією ['w','o','r','l','d']. Якщо в масиві занадто мало або занадто багато елементів, щоб він не відповідав рядку формату, з’являється помилка. Ахілесова п’ята - це те "%c"*5, що %w(w o r l d)може існувати і незалежно, і $><<потрібен лише аргумент будь-якого. Отож, існує кілька різних способів залучення цієї програми до двоюрідних братів.


Перевірено за допомогою цього:

s = 'eval(*[($>.write("world")-1).chr])'
puts s.size
(1...s.length).each do |len| #how much to remove
  (0...len).each do |i| #where to remove from
    to_test = s.dup
    to_test.slice!(i,len)
    begin #Feels so backwards; I want it to error and I'm sad when it works.
      eval(to_test)
      puts to_test
      puts "WORKED :("
      exit
    rescue SyntaxError
      #Have to have a separate rescue since syntax errors
      #are not in the same category as most other errors
      #in ruby, and so are not caught by default with 
      #a plain rescue
    rescue
      #this is good
    end
  end
end

Пояснення у відповідь гістократа було б добре. Схоже, ви використовуєте той самий базовий підхід, але оскільки я не знаю Рубі, я не можу зрозуміти деталі.
ThisSuitIsBlackNot

@ThisSuitIsBlackNot Я зробив все можливе, що ви не розумієте?
Шельваку

Відмінне пояснення, дякую!
ThisSuitIsBlackNot

6

Python 3 , 43 байти

for[]in{5:[]}[open(1,"w").write("world")]:a

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

Як це працює

Для захисту від видалення підрядків ми використовуємо open(1,"w").writeзамість цього print. У Python 3 writeповертає кількість написаних символів, за якими ми перевіримо, 5щоб жодна частина рядка не була видалена. Ми робимо це, шукаючи повернене значення у словнику {5:[]}та перебираючи результат на for[]in…:a, який не вдасться, якщо ми не отримали порожній ітерабельний або якщо forвиписку буде видалено.


4

Javascript (Node.js), 93 95 байт

if(l=arguments.callee.toString().length,l!=158)throw l;console.log("world");if(g=l!=158)throw g

Перевірте свій власний розмір двічі, щоб у разі відсутності символів сталася помилка. Довжина - 156, оскільки Node.js претендує function (exports, require, module, __filename, __dirname) {на код під час виконання.

Дякую Мартіну Бюттнеру за вказівку на помилку. Виправлено зараз.


4

Perl 5,10+, 71 63 байт

(${open 0;@{\(read(0,$a,63)!=63?die:@_)};say"world"});{$a//die}

Друкується worldіз заднім рядком. Бігайте так:

perl -M5.010 file

Це спирається на кількість байтів вихідного коду, тому fileповинно містити наведений вище код і нічого іншого (ні шебанг, ні трейлінг нового рядка). Perl 5.10+ потрібен sayі для оператора, визначеного або визначеного //.


Зробити первозданну програму з Perl неймовірно складно, тому що:

  • Будь-ідентифікатор bareword (наприклад foo, a, _) є допустимим заяву з no strict 'subs';(за замовчуванням). Це означає, що програма не може ні починати, ні закінчуватися літерою, цифрою або підкресленням.

  • Як пояснює tchrist , "Ідентифікатори, вказані за допомогою символічної перенаправлення, абсолютно не обмежують своїх імен". Це означає , що програма не може починатися з будь-якого з сігіли $, @, %або *, так як видалення всіх , крім першого і останнього символу завжди буде залишати правильне ім'я змінної.

  • Багато вбудованих функцій (включаючи більшість функцій, здатних виробляти вихід) працюють $_за замовчуванням, тому дзвінки часто працюватимуть, навіть якщо ви видалите аргумент (наприклад, say"world"проти say).

Як це працює

Це рішення було натхнене відповіддю Node.js Naouak , яка перевіряє власну довжину, щоб переконатися, що символи не були видалені.

Програма має два розділи, один всередині дужок, а другий всередині блоку:

(...);{...}

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

Видалення середньої або лівої чи правої частини програми призведе до врівноваження дужок та / або фігурних дужок, що спричинить синтаксичну помилку.

Якщо перший dieзмінюються (з d, e, di, de, або ie, що всі дійсні ідентифікатори), то перевірка довжини стає:

@{\(read(0,$a,63)!=63?di:@_)};

який оцінює:

@{\'di'};

Це посилається на рядок і намагається знеструмити його як масив, викликаючи помилку:

Not an ARRAY reference

Якщо будь-яке інше твердження буде змінено, перевірка довжини не вдасться, і програма загине.


Перевірено незаймане за допомогою наступної програми:

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;

use File::Temp;
use List::MoreUtils qw(uniq);

sub delete_substr {
    my ($str, $offset, $len) = @_;

    my $tmp = $str;
    substr($tmp, $offset, $len) = '';

    return $tmp;
}

sub generate_subprograms {
    my ($source) = @_;

    my $tot_len = length $source;
    my @subprograms;                                             

    foreach my $len (1 .. $tot_len - 1) { 
        foreach my $offset (0 .. $tot_len - $len) {
            push @subprograms, delete_substr($source, $offset, $len);
        }                                                        
    }                                                            

    return uniq @subprograms;                                    
}                                                                

chomp(my $source = <DATA>);                                                                                                       
my $temp = File::Temp->new;                                                                                        

foreach my $subprogram ( generate_subprograms($source) ) {       
    print $temp $subprogram;

    my $ret = system(qq{/usr/bin/perl -M5.010 $temp > /dev/null 2>&1});
    say($subprogram), last if $ret == 0;

    truncate $temp, 0;
    seek $temp, 0, 0;
}

__DATA__
(${open 0;@{\(read(0,$a,63)!=63?die:@_)};say"world"});{$a//die}

4

Ruby + coreutils, 33 27 26 байт

`base#{$>.write"world
"}4`

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

Повернення в рубіні виконує команду всередині них і повертає програму STDOUT як рядок. #{expr}Синтаксис дозволяє вбудовування виразів в рядках і зворотних лапках. Ця програма може бути переписана (не первинно) у вигляді:

system("base" + (STDOUT.write("world\n")).to_s + "4")

IO#writeповертає кількість написаних байтів, тож якщо рядок скорочено, це не буде правильним числом. #{}вбудовування автоматично перетворює число в рядок. Якщо якийсь фрагмент буде видалений, і це не призведе до синтаксичної помилки, буде запущена неправильна команда. Якщо частина "world"вилучена, ніж один base04прохідний base54спробує запустити.

Новий рядок, входити чи виходячи з рядка, обов'язковий. В іншому випадку перші 5 символів ( `base) можна видалити, зробивши весь коментар рядком. Також між першим backtick має бути один або декілька символів #, інакше {можна видалити, щоб зробити все це коментарем оболонки .


exec(*[(s="ec%co earth")%s[10]])

execЗамінює поточний процес рубіну вказаною командою. Дивіться іншу мою відповідь щодо пояснення meth(*[])синтаксису та необхідності його.

(s="ec%co earth")присвоює рядку "ec% co земля" змінної s. Завдання повертають те, що було призначено, тому рядок також повертається.

"format string %d" % 5є синтаксичним цукром для sprintf("format string %d",5), проте пробіли навколо %не є необхідними.

s[10]отримує символ у рядку з індексом 10. Якщо не відрегульовано, цей символ є "h", остання літера в рядку. Однак видалення будь-яких символів у рядку означає, що рядок коротший, тому символу в індексі 10 немає, тому s[10]повертається nilта "%c" % nilвикликає помилку.

якщо %s[10]видалено, то рубін намагається запустити команду, ec%co earthяка не працює.

Зміна 10до 1або 0також призводить до невідомої команді (або eceoчи ecco). Видалення його повністю технічно не є синтаксичною помилкою, оскільки він викликає метод #[]у рядку, але потім він скаржиться на недостатньо аргументів.


Примітка щодо вирішення цього питання в цілому: Ви повинні мати обгортку, яка перевіряє код всередині в абстрактному розумінні, будучи первозданною. Наприклад, програма з поділом в кінці ( blablabla/somevar) ніколи не працюватиме, оскільки поділ завжди можна видалити ( blablabla). Ось такі обгортки я використовував досі:

  • eval(*[код, ])використаний гістократом і в моїй першій відповіді. Перевіряє, що вихід є дійсною програмою рубіну
  • exec(*[Код, ])використаний вище, підтверджує, що відповідь є дійсною командою
  • `#{ код }`

Синтаксис backtick також виконує команду (і для цього підтверджує, що вона є дійсною), проте STDOUT фіксується як рядок, а не виводиться як батьківський процес '(Ruby's) STDOUT. Через це я не зміг використати його для цієї відповіді, EDIT: Я змусив її працювати. Обмеження, окреслені вище.

Редагування: Дякуємо @histocrat за вказівку на деякі недоліки


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

@histocrat Вау, я здивований, що $>.write"world"працює, дякую! Що стосується base64, що чекає на введення, воно, схоже, змінюється в залежності від системи. TIO працює чудово. Це робить його ще більш нечітким щодо того, чи дотримується він правил.
Шельваку

3

PowerShell, (97 байт + 5 для назви програми) = 102 байти

"$(try{if(($a=(gc .\c.ps1).Length)-eq97){"world";a}}catch{if($a-ne97){a}$error.clear();exit}a)";a

Перевіряє себе, перш ніж вона зазнає краху ... двічі.

Очікую , що будуть збережені як c.ps1і виконуються з локального каталогу як такі:
PS C:\Tools\Scripts\Golfing\> .\c.ps1.

Псевдонім gcкороткий Get-Contentі схожий на catчитання файлу (у цьому випадку наш шлях виконання .\c.ps1). Отримуємо .Lengthфайл, встановлюємо його $aі перевіряємо, чи він не дорівнює 97 с -eq97. Якщо вона дорівнює (тобто програма не була змінена), ми друкуємо за допомогою "world"і виконуємо недійсну команду a. Це змушує catchнабути чинності, що дозволяє нам перевірити себе ще раз. Цього разу, якщо наш код не дорівнює 97, ми кидаємо недійсну команду, щоб наша програма помилилася і надрукувала текст помилки на вихід. Ми тоді clear()помилка і exitнормально.

Очевидно, що якщо будь-яке ifтвердження буде підроблене, інше матиме помилку. Якщо будь-яка порція "world";підроблена, перша ifпризведе до помилки. Оскільки це повинно бути суміжним, ми не можемо видалити обидва ifтвердження. Рядки в середині призведе до невідповідних дужок або призведе до другого {a}виконання. try/ catchЩоб зловити помилку від першого ifзаяви , щоб ми могли належним чином очистити його. Зовнішні "$( )"рядки не дозволяють отримати будь-який кінець. Останнім ;aє запобігання того, щоб частини середини не потрапляли в осередок, що призвело б до дійсних програм (наприклад "it}a)";a, які надрукують it}a)і потім помиляться).

Існує кілька особливих обставин:

  • Якщо gc, gc<space>або gc .\видаляються, програма, в кінцевому рахунку помилки з деяким присмаком амбулаторної помилки пам'яті (з - за повторні виклики самостійного виконання) і , ймовірно , аварією оболонка (і , можливо, комп'ютер). Не перевірений.
  • Якщо <space>.\c.ps1або .\c.ps1видалено, програма зупиниться та запропонує ввести користувач. Незалежно від того, що вводить користувач, програма все одно буде помилятися, оскільки підрахунок розмірів буде неправильним.
  • Якщо підрядок, що починається на $і закінчується до того, як "буде зроблено останній , програма виведе все, що залишилося, а потім помилка, оскільки aне є дійсною.

Підтверджено наступним:

$x='"$(try{if(($a=(gc .\c.ps1).Length)-eq97){"world";a}}catch{if($a-ne97){a}$error.clear();exit}a)";a'
$yy='"$(try{if(($a=( .\c.ps1).Length)-eq97){"world";a}}catch{if($a-ne97){a}$error.clear();exit}a)";a'
$yyy='"$(try{if(($a=(.\c.ps1).Length)-eq97){"world";a}}catch{if($a-ne97){a}$error.clear();exit}a)";a'
$yyyy='"$(try{if(($a=(c.ps1).Length)-eq97){"world";a}}catch{if($a-ne97){a}$error.clear();exit}a)";a'

for($i=1;$i-lt$x.Length;$i++){
  for($j=0;$j-lt($x.Length-$i);$j++){
    $y=($x[0..$j]+$x[($i+$j+1)..$x.Length])-join''
    $y>.\c.ps1
    $error.clear()
    if(!($y-in($yy,$yyy,$yyyy))){try{.\c.ps1}catch{};if(!($error)){exit}}
    $q++;
    write-host -n "."
    if(!($q%150)){""}
  }
}
"No success."

(Дякую Мартіну за велику допомогу!)


3

C (gcc) (Linux, -Werror=undef), 66 байт

main(a){a
=
1
/
(puts("world")/
6);
#if(7^__LINE__)
#else
}
#endif

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

Великий виклик! Це було оманливо важко, але я майже впевнений, що зараз у мене дієва програма!

Використовує команду препроцесора, щоб не можна було видалити нові рядки, оскільки дужка закриття до mainвходить лише у випадку, якщо __LINE__==6. Це також утримує вас від простого очищення mainповністю, оскільки це листя #endifплаває (тому важливо, що #endifзнаходиться поза main).

Я використовував, #elseтому що я переконався, що не існує версії, __LINE__==6яка не може видалити підрядку, і все-таки є правдою, оскільки 6і __LINE__самі по собі є правдою. Він також використовує -Werror=undefтак, що щось на зразок #ifdef(LINE__)не оцінюється як хибне, але є помилкою.

Якщо gcc (як мінімум, в Linux) putsповертає кількість надрукованих символів (включаючи кінцевий новий рядок), тому видалення будь-якої частини рядка робить puts("...")/6повернення 0, що 1/0спричиняє виняток із плаваючою комою. Зауважте, що цей виняток не викликається, якщо 1/0щось не призначено, тому a=потрібне.

Жодна інша частина будь-якого рядка не може бути видалена без створення помилки, як правило, синтаксична помилка чи помилка зв’язку.

Як бонус, це дає 86-байтне рішення для C ++ досить тривіально, просто додайте #include <cstdio>та оголошуйте aяк int. Спробуйте в Інтернеті! (C ++)


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

@gastropner Право ти є. 1повинен був у попередньому рядку я вважаю.
Кріс

На жаль, це те саме. Потім можна видалити =1. Я думаю, вам потрібно поставити 1 на рядок самостійно.
гастропнер

@gastropner Я думаю, ти маєш рацію. Подивлюся пізніше. Дякую!
Кріс

2

PHP, 73 байти

<?=call_user_func(($p='ns')|(($f="u{$p}erialize"))?$f:'','s:5:"world"');

Роз'яснення

Я припускаю конфігурацію php.ini за замовчуванням. Тож short_tags вимкнено. Це означає, що ви не можете видалити =тег із відкриття тегу.

Це в основному <?=unserialize('s:5:"world"');.

Якщо ви видалите будь-яку частину серіалізованого рядка, ви отримаєте помилку.

Ви можете просто видалити, unserializeі сценарій просто виведе серіалізований рядок. Для подолання цього я використовую call_user_func. Видалення одного з параметрів призведе до помилки.

'<?=call_user_func('unserialize','s:5:"world"');

Однак ви можете вилучити функцію unдля виклику serialize. Тож ми виймаємо «нс». Видалення будь-яких символів не призведе до неправильного імені функції.

<?=call_user_func(($p='ns')&&($f="u{$p}erialize")?$f:'','s:5:"world"');

Ми будемо використовувати вбудований рядок, якщо використовувати змінне призначення з вихідним тегом. Замість використання &&ми використовуємо "|" щоб запобігти видаленню одиночного &або видаленню $fзавдання

Ви можете видалити ='ns')&&($f="u{$p}erialize"і закінчити ($p)?$f:''. Для цього я додаю додаткові дужки навколо $f="u{$p}erialize".

Примітка

Технічно ви можете видалити вступні теги, не створюючи помилок. Однак це вже не сценарій PHP, а просто звичайний текстовий файл.


2
Щодо вашої останньої примітки, звичайний текстовий файл все ще буде дійсною програмою PHP, правда? Тож я не впевнений, що це справедливо.
Захоплення Кальвіна

Це вже не PHP, а відкритий текст / html, таким чином, більше не є дійсною програмою php
Martijn

1

Матлаб (77)

bsxfun(@(c,b)arrayfun(@(x)getfield(c,{x}),conv(b,ismember(4,b))),'world',1:5)

Спробуй це

Примітка:

Дотримуючись поради @ Optimiser щодо створення CPR чи чогось іншого, я зіткнувся з непередбачуваною підрядкою, яка не призвела до будь-якої помилки компіляції при видаленні, наприклад: видалення arrayfun(@(x)a(x),prod(b,ismember(4,1:5))),з цього попереднього редагування feval(@(a)arrayfun(@(x)a(x),prod(b,ismember(4,1:5))),'world')не створює помилок! також, для недавнього ж видання, було, bsxfun(@(a,b)arrayfun(@(x)(x),prod(b,ismember(4,b))),'world',1:5)і bsxfun(@(a,b)a,'world',1:5)якщо ви запитали про те, як я знаходив їх у своїй вихідній консолі, я плакав, як дитина, ось ось програма:

b=0;string='bsxfun(@(c,b)arrayfun(@(x)getfield(c,{x}),conv(b,ismember(4,b))),''world'',1:5)'
for u=1:numel(string),for j=u:numel(string)-2,try a=eval([string(1:u) string(j+2:end)]);catch(b); a=0;end; if a~=0, ['here is it : ' string(1:u) string(j+2:end)],end;end;end

Приклад безкорисної програми

редагувати:

Дякую всім поруч із @Martin за вказівку моїх попередніх кодів (не помилок).


1

SmileBASIC, 63 байти

REPEAT
A=1/(PRGSIZE(0,1)==63)?"world
UNTIL 1/(PRGSIZE(0,1)==63)

1

Дерево груші , 17 байт

Ця програма містить байти з високим набором бітів (які не є дійсними UTF-8 і тому не можуть бути розміщені в TIO), тому ось xxdзворотний гексад:

00000000: 7072 696e 7427 776f 726c 6427 23cd 4290  print'world'#.B.
00000010: bf                                       .

Пояснення

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

Досить нудно, але зв’язує нинішнього керівника, тому я відчув, що варто відправити повідомлення.

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