Программирование первозданного мира


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

Ответы:


47

Rail , 24 байта

$'main'    #
 -[world]o/

Я думаю, что это работает. И это и кратко и читабельно (насколько Rail идет).

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

Что касается фактической программы: каждая железнодорожная программа должна иметь $'main'(или более длинный вариант, но мы здесь играем в гольф) в качестве точки входа в функцию, и поезд начинает $движение на юго-восток. Все в этой первой строке может быть частью трека, поэтому удаление 'main'трека это:

$          #
 -[world]o/

-И /просто куски рельса , которые мы должны позволить поезду взять эти 45 ° поворотов.

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

Интересно, что это решение возможно только потому, что Rail позволяет трекам проходить mainлинию - если это невозможно, #это будет после первой новой строки, и код всегда можно будет сократить до

$'main'
 #

которая является действительной программой, которая ничего не делает. (Не пробелы между 'и #не влияют на это.)

Также довольно интересно: если бы я только играл в гольф для печати задач, 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
Я чувствую, что вам повезло в последнем случае (не то, что так легко случайно получить действительную последовательность Юникода, но все же ...)
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
@ Коминтерн, не совсем. Если вы не установите флажок для запуска исполняемого файла, /cопция автоматически включается и компилируется (как будто создается библиотека, а не программа). Если вы установите флажок запуска, который сайт не включает /c, вы не получите сообщение об успешном завершении, а вместо этого найдете естественное «LINK: фатальная ошибка LNK1561: должна быть определена точка входа».
Линус

32

Python 3, 79 33

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

open(1,'w')открывает стандартный вывод, затем мы печатаем строку. writeвозвращает количество написанных символов. Это используется для защиты от удаления подстроки: удаление части строки приводит к возвращению чего-то, отличного от 5, а затем 5 минус это значение оценивается как true. Но это вызывает выполнение if-body и aне определено.

Это основано на умных нетронутых Quine Андерс 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

Функцион , 143 142 136 байт

Счет в UTF-8 как обычно, так как UTF-16 будет на два байта больше (из-за спецификации).

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

Итак, я некоторое время обдумывал ответ Funciton, и я подумал, что это будет невозможно, потому что вы всегда можете удалить полную строку, а код все равно будет формировать действительный блок. Затем я поговорил с Тимви об этом, и он понял, что вы можете просто поместить все число в одну строку, так что его удаление сломало бы программу из-за отсутствия выходного разъема.

Но литералы в одной строке общеизвестно дороги, как из-за большего количества символов, так и из-за большего количества символов не-ASCII. И его упоминание о блоке "пустой комментарий" заставило меня задуматься ...

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

  • Мы не можем удалить третью строку, потому что тогда мы удалили бы выходной разъем.
  • Если мы удалим вторую строку, блок комментария теряет свой верхний край и разрывается.

Это оставляет два варианта (спасибо Стиву за указание на это):

  • Удалить четвертую строку. Это оставляет обе коробки в такте. Тем не менее, когда полученное целое число 19342823075080880373декодируется, соответствующая строка будет содержать кодовую точку, 0x18D53Bкоторая не является допустимым символом Unicode, System.Char.ConvertFromUtf32сбой с ArgumentOutOfRangeException.
  • Удалить полную строку, начинающуюся после правого верхнего угла. Опять же, оба поля остаются в такте, но полученное целое число 508088037380718711будет содержать две недопустимые кодовые точки 0x1B0635и 0x140077, что приведет к тому же исключению.

Обратите внимание, что даже без пустого блока комментария удаление второй строки приведет к неверной кодовой точке. Но комментарий блок предотвращает , что мы берем линию от внутри второй линии, чтобы получить целое число , как 193428037380718711, например, что не вызвало бы ошибку.


Что произойдет, если вы удалите подстроку, начинающуюся с символа после выходного соединителя и заканчивающуюся ровно на 1 строку позже? т.е. удаление средней строки блока комментариев и строки, содержащей «80718711» в главном блоке, но оставляя углы обоих полей нетронутыми.
Стив

@ Стив, я исправил ответ, чтобы покрыть это дело. После более подробного изучения это позволило мне сохранить два символа / шесть байтов.
Мартин Эндер

10

Руби, 36

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

Мы назначаем s="planet", а затем записываем эту строку в STDOUT. Это возвращает количество написанных символов. Мы переписываем это с помощью 6, чтобы, если было написано что-либо кроме 6 символов, мы получили ненулевое целое число. Затем мы разрезаем sэтот индекс. Только 0-ый символ s, «p», является допустимой строкой кода (без операции). Мы передаем это 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'вызывает ошибку, потому что массив символов инициализируется с длиной 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 дополнительное условие preproc может быть удалено.

Привет, спираль! Как вы думаете, вы могли бы объяснить, как и почему ваш ответ работает немного больше?
Исаак

@isaacg Отредактировано. Доказательство, чтобы следовать.
Helix Quar

Я не могу заставить его работать без staticна Main.
Johnbot

@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
Johnbot

9

MATLAB, 37 36 33 байта

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

Поскольку я не уверен, что нам разрешено выводить ans = , мне пришлось найти обходной путь для правильного вывода. Использование fprintf само по себе не сработало, потому что, что бы я ни пытался, он просто отказывался от ошибок. Использование disp само по себе не было вариантом, так как он принимал бы только 1 аргумент, и сам этот аргумент, очевидно, также выполнялся бы без ошибок.

Если нет проблем также включить ans = в вывод, тогда MATLAB может быть выполнен с 20 байтами :

reshape('world',1,5)

я действительно должен узнать больше о встроенных функциях (+1) // кстати, ваша программа
получила

2
Это действительно зависит от того, насколько строгие правила. Они утверждают, что должен быть напечатан только «мир» (+ необязательный завершающий символ новой строки), поэтому это 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было несколько странных подпрограмм, которым удалось использовать команду put, чтобы поместить вместо [очищенной стека команду, которая очистит стек A. Кроме того, «земля» - единственная из фраз, которая будет работать с этим методом, потому что первая буква eявляется допустимой инструкцией в ><>. В противном случае "команда должна быть размещена в начале программы, и допустимая подпрограмма может быть "сама по себе.


8

Руби, 34

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

Это имеет несколько компонентов:

eval(*[ expr ]) заимствован из ответа гистократа и является чистым , так как проверка возвращаемого значения expr является допустимой программой ruby, которая не выдает ошибку. 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 и в противном случае возвращает односимвольную строку.

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

$>.write("planet
")*16

где «планета» плюс символ новой строки были 7 символов, умноженные на 16, чтобы получить 112 p, единственная однобуквенная функция в ruby, определенная по умолчанию. Когда нет аргументов, это фактически не


Похвальный отзыв: $><<"%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

Объяснение в духе ответа гистократа было бы неплохо. Кажется, вы используете тот же базовый подход, но, поскольку я не знаю Ruby, я не могу понять детали.
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-программу с Perl невероятно сложно, потому что:

  • Любой идентификатор bareword (например foo, a, _) является допустимым заявление с no strict 'subs';(по умолчанию). Это означает, что программа не может ни начинаться, ни заканчиваться буквой, цифрой или подчеркиванием.

  • Как объясняет Черст , «идентификаторы, указанные посредством символьной разыменования, не имеют абсолютно никаких ограничений на свои имена». Это означает , что программа не может начинаться с любого из сигилы $, @, %или *, так как удаление всех , кроме первого и последнего символа всегда будет оставлять правильное имя переменной.

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

Как это устроено

Это решение было вдохновлено ответом Науака Node.js , который проверяет собственную длину, чтобы убедиться, что символы не были удалены.

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

(...);{...}

Первый раздел читает исходный файл и умирает, если его длина менее 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`

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

Обратные пометки в ruby ​​выполняют команду внутри них и возвращают все, что программа поместила в STDOUT в виде строки. #{expr}Синтаксис позволяет встраивание выражений в строках и обратных кавычках. Эта программа может быть переписана (нетрадиционно) как:

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

IO#writeвозвращает количество записанных байтов, поэтому, если строка укорочена, она не будет правильным числом. #{}встраивание автоматически превращает число в строку. Если какая-то часть будет удалена, и это не приведет к синтаксической ошибке, будет выполнена неправильная команда. Если часть "world"удалена, то один из base04сквозных base54будет пытаться запустить.

Требуется новая строка, внутри или вне строки. В противном случае первые 5 символов ( `base) могут быть удалены, что делает всю строку комментария. Также между первым обратным трюком и должен быть один или несколько символов #, в противном случае их {можно удалить, чтобы сделать все это комментарием оболочки .


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

execЗаменяет текущий процесс ruby ​​указанной командой. Смотрите мой другой ответ для объяснения meth(*[])синтаксиса и необходимости его.

(s="ec%co earth")присваивает строку "ec% co earth" переменной s. Назначения возвращают то, что было назначено, поэтому строка также возвращается.

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

s[10]получает символ в строке с индексом 10. При отсутствии искажения этот символ является «h», последней буквой в строке. Однако удаление любых символов в строке означает, что строка короче, поэтому в индексе 10 нет символа, поэтому s[10]возвращается nilи "%c" % nilвызывает ошибку.

если %s[10]удалено, то ruby ​​пытается запустить команду, ec%co earthкоторая не работает.

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


Замечание по решению этой проблемы в целом: у вас должна быть некоторая обертка, которая проверяет код внутри в абстрактном смысле, оставаясь при этом самой чистой. Например, программа с разделением в конце ( blablabla/somevar) никогда не будет работать, потому что разделение всегда можно удалить ( blablabla). Вот некоторые из таких оболочек, которые я использовал до сих пор:

  • eval(*[код, который ])использовал гистократ и в моем первом ответе. Проверяет, что вывод является действительной программой ruby
  • exec(*[код, ])использованный выше, подтверждает, что ответ является допустимой командой
  • `#{ код }`

Синтаксис backtick также запускает команду (и поэтому подтверждает, что она действительна), однако STDOUT записывается как строка, а не выводится как родительский процесс '(Ruby's) STDOUT. Из-за этого я не смог использовать его для этого ответа, РЕДАКТИРОВАТЬ: я сделал это работает. Ограничения изложены выше.

Редактировать: Спасибо @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"');

Explination

Я предполагаю, что конфигурация 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"');

Мы будем использовать inline, если использовать переменную с тегом output. Вместо использования &&мы используем '|' чтобы предотвратить удаление одного &или удаления $fназначения

Вы можете удалить ='ns')&&($f="u{$p}erialize"и в конечном итоге ($p)?$f:''. Поэтому я добавляю дополнительные скобки вокруг $f="u{$p}erialize".

Запись

Технически вы можете удалить открывающие теги, не вызывая ошибки. Однако это уже не PHP-скрипт, а просто текстовый файл.


2
Что касается вашей последней заметки, простой текстовый файл все равно будет действительной программой PHP, верно? Так что я не уверен, что это действительно.
Увлечения Кэлвина

Это больше не PHP, а обычный текст / html, таким образом, больше не является действующей php-программой
Martijn

1

Matlab (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обратимый hexdump:

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.