Сделайте свой язык * в основном * непригодным (нить грабителя)


31

Вдохновленный этим комментарием ...

Спасибо пользователям Step Hen , Wheat-Wizard и Dennis за помощь в разработке спецификации этого задания перед его публикацией!

Это нить грабителя! Для нити ментов, иди сюда


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

  • Возьмите числовой ввод и вывод

  • Добавьте два числа вместе

  • Проверьте, является ли определенное число простым или нет.

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

Полицейские напишут два фрагмента кода:

  1. Тот, который делает их язык в основном непригодным, например, удаляя встроенные функции для ввода / вывода и числовые операции. Этот код не может произойти сбой или выход. Должна быть возможность добавить код в конец этого фрагмента, и этот код будет оценен . А также

  2. Фрагмент кода, который принимает два числа в качестве входных данных, складывает их вместе и выводит их сумму. Этот фрагмент должен работать правильно даже после запуска первого фрагмента. Когда два фрагмента объединены вместе, они должны сформировать полную программу, которая добавляет два числа, или определить функцию, которая добавляет два числа. Этот фрагмент, вероятно, будет опираться на неясное поведение, и его будет трудно найти.

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

Ответ ментов всегда откроет

  • Первый фрагмент (явно не второй).

  • Язык (включая минорную версию, так как большинство представлений, вероятно, будет опираться на странные крайние случаи)

  • Формат ввода-вывода, в том числе ли это функция или полная программа. Грабители должны использовать тот же формат, чтобы быть действительным взломом.

  • Любые странные крайние случаи, необходимые для их ответа на работу. Например, работает только на Linux или требует подключения к Интернету .

Как грабитель, вы должны посмотреть на одно из представлений полицейских и попытаться взломать его. Вы можете взломать его, написав любой допустимый фрагмент кода, который мог бы работать как фрагмент 2 (сложение двух чисел после того, как язык стал в основном непригодным для использования). Это не должен быть тот же фрагмент, который первоначально написал полицейский. После того, как у вас есть взломанный ответ, опубликуйте свой код как ответ в этой теме и опубликуйте ссылку на свой ответ в качестве комментария к ответу полицейского. Затем это сообщение будет отредактировано, чтобы указать, что оно взломано.

Вот пример. Для первого фрагмента вы можете увидеть следующую программу на Python 3 в качестве ответа полицейского:

Python 3

print=None

Принимает ввод из STDIN и вывод в STDOUT

Допустимый второй фрагмент может быть

import sys
a,b=int(input()),int(input())
sys.stdout.write(a+b)

Это верно, потому что он будет принимать два числа в качестве входных данных и выводить их сумму, даже если вы соедините два фрагмента вместе, например

print=None
import sys
a,b=int(input()),int(input())
sys.stdout.write(a+b)

Это действительный треск к их ответу.

Если ответ копа остается без изменений в течение целой недели, он может отредактировать свой второй фрагмент и указать, что его ответ теперь безопасен . После того, как он отредактирован, чтобы быть безопасным, вы можете больше не пытаться взломать его. Если они не редактируют это как безопасное, вы можете продолжать пытаться взломать его, пока они не сделают это.

Победителем темы грабителя является пользователь, взломавший наибольшее количество ответов, причем тай-брейк - это время, когда они достигли N трещин. (например, если два разных пользователя имеют по 5 крэков, например, пользователь, который первым разместил свой 5-й крэк, является победителем). По истечении достаточного времени я приму ответ победителя с наибольшим количеством голосов.

Повеселись!

Разъяснения правил

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

  • Второй фрагмент должен быть действительно выполнен, чтобы ваш ответ был действительным. Это означает, что ответ как

    import sys
    sys.exit()
    

    недопустимо, потому что это не нарушает язык. Это просто выходит.

  • После того, как вы в безопасности, ваш счет - это количество байтов обоих фрагментов .

  • Это восходит к Пожалуйста , выявить какие - либо странные случаи края , необходимые для ответа на работу ... Ваша заявка должна содержать достаточно информации , прежде чем раскрывается воспроизводимыми после раскрывается. Это означает, что если ваш ответ станет безопасным, а затем вы отредактируете в: Вот мой ответ. Да, кстати, это работает, только если вы запускаете его на Solaris, шутки над вами! Ваш ответ недействителен и будет удален и не будет признан приемлемым для победы.

  • Второй фрагмент может потерпеть крах после вывода суммы. Пока вывод по-прежнему правильный (например, если вы выберете вывод в STDERR, а затем получите кучу информации о сбое, это недопустимо)

Leaderboard

Вот список каждого пользователя, у которого есть хотя бы один треск, упорядоченный по счету, а затем по имени (в алфавитном порядке). Если вы отправите трещину, пожалуйста, обновите ваш счет соответственно.

#User                       #Score
Ilmari Karonen              8

Dennis                      5

Olivier Grégoire            4

Sisyphus                    3
Veedrac                     3

Arnold Palmer               2
Bruce Forte                 2
DJMcMayhem                  2
Dom Hastings                2
ppperry                     2

1bluston                    1
2012rcampion                1
Ben                         1
BlackCap                    1
Christian Sievers           1
Cody Gray                   1
HyperNeutrino               1
Joshua                      1
Kaz                         1
Mark                        1
Mayube                      1
Xnor                        1
zbw                         1

Ответы:


3

Java 8 Оливье Грегуар

class A {
  public A() {
    String[] args = System.lineSeparator().split(",");
    System.out.print(Integer.parseInt(args[0]) + Integer.parseInt(args[1]));
  }
}

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

Поскольку Оливье явно разрешил передачу ввода через свойства, заданные с помощью аргументов VM, я укажу, что ввод должен быть указан в аргументе VM -Dline.separator=X,Y, где Xи Y- это числа, которые будут добавлены. То есть, например, чтобы добавить числа 17 и 25, программа должна быть вызвана как:

java -Dline.separator=17,25 Main

Я считаю, что это должно работать на любой системе, которая может запускать программы Java из командной строки. Даже в системах, в которых нет командной строки, любой другой эквивалентный механизм настройки системных свойств может быть использован для передачи ввода в ВМ.


Ps. Вот моя более ранняя попытка взлома, которая была признана недействительной из-за использования специфических функций JVM:

class SecurityManager extends sun.awt.AWTSecurityManager {
  static {
    String[] args = System.getProperty("sun.java.command").split(" ");
    int a = Integer.parseInt(args[args.length-2]);
    int b = Integer.parseInt(args[args.length-1]);
    System.out.println(a+b);
  }
}

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

Это оказалось намного менее многословным, чем предыдущий . Сложнее всего было найти подкласс, SecurityManagerкоторый не жил в пространстве имен, начинающемся с " java.". Я подозреваю, что это все еще не предполагаемое решение, но оно работает. *

*) По ТИО, как минимум; sun.awt.AWTSecurityManagerкласс и sun.java.commandсвойство , кажется, не быть официально зарегистрированы, и не могут быть доступны на всех виртуальных машинах.


Хорошая работа! Я попробовал это, но не смог найти объект, SecurityManagerкоторый был в области видимости ... Вы также можете прочитать с System.inэтого момента, потому что он еще не закрыт.
zbw

Извините, это платформо-зависимый ответ в двух отношениях: оба sun.awt.SecurityManagerи "sun.awt.command"зависят от платформы и не являются частью Java .
Оливье Грегуар,

Да, треснул! :) Предполагаемое решение состояло в том, чтобы пройти через System.getProperties().get("blah")(так как я только заблокировал доступ System.getProperty, не System.getProperties), но этого достаточно хорошо! Отлично сработано!
Оливье Грегуар

22

C (GCC / Linux) от Sisyphus

Этот фрагмент закрывает предоставленную функцию и запускает новую (классическая инъекция кода), которая сама по себе переопределяет, closeтак что вместо закрытия fd запускается наш нужный код.

}
int close(int x) {
  int a, b;
  scanf("%d %d", &a, &b);
  printf("%d\n", a + b);

  exit(0);

20

Python, решение для мастера по пшенице здесь

import sys
c="".join(open(__file__).read().split('\n')[4:])
if set(c)-set(' &)(,.:[]a`cdfijmonrt~')or"import"in c:sys.setrecursionlimit(1)
f=lambda\
:[]                                                      # my code starts here
sys.setrecursionlimit(1000)
print(int(input())+int(input()))

Я имею в виду, вы можете просто установить предел рекурсии, и ничего плохого не случится ...

Работает на TIO

Заметка

Это моя первая CnR-заявка, поэтому, если это нарушает какие-либо правила, пожалуйста, сообщите мне, и я удалю это.


4
Я глуп, что пропустил это
Мастер Пшеницы

@WheatWizard :)
HyperNeutrino

@wheatwizard Пока не раскрывайте предполагаемое решение. Я бы хотел увидеть лучшего копа с вашим оригинальным решением, которое решит эту проблему.
DJMcMayhem

@Djmcmayhem Я, вероятно, собираюсь сделать репост с del sys.
Пшеничный волшебник

@WheatWizard Помните os.sys, если это имеет значение: P
HyperNeutrino

15

Хаскель Бен

import Prelude(getLine,print)
a=a
[]++s=s
(a:as)++s=a:(as++s)
r""=""
r(c:s)=(r s)++[c]
t(_:r)=r
ts l=l:ts(t l)
x[_](v:_)=v
x(_:r)(_:s)=x r s
d(a:_:_:_:_:_:_:_:_:_:r)=a:d r
(a:_)!!""=a
l!!(n:m)=d(x['0'..n](ts l))!!m
a+b=[[0..]!!a..]!!b
a-b=let n=[0..]!!a;m=[0..]!!b in
    case [n..m] of
      [] ->   x[m..n][0..]
      l  -> -(x l    [0..])
add('-':x)('-':y)= -(r x+r y)
add('-':x)y=r y-r x
add x('-':y)=r x-r y
add x y=x+y
main=do a<-getLine;b<-getLine;print(add a b)

У меня все еще есть буквальные числа и символы (я использую 0, '0'и '-'), [a..]и [a..b]которые очень полезны. И у меня одинарные -, но я мог бы обойтись без.

Я воссоздаю ++для реализации r( reverse) и определить, tа tsкакие tailи tails. x a bвозвращает nэлемент th b, где nдлина aминус один. xобычно можно определить как snd.last.zip. Функция dберет список и возвращает список с элементами из тех позиций, которые кратны десяти. l!!sвозвращает nэлемент th l, где s- обратное строковое представление n. +возвращает в виде целого числа сумму двух натуральных чисел, заданных в виде перевернутых строк, аналогично -разнице. addвозвращает как целое число сумму двух возможно отрицательных целых чисел, заданных в виде строк.

Интересно, похоже ли это на то, что имел в виду Бен.


Да, почти такие же идеи. Сравнение шаблонов с литералами для получения тестов на равенство и ветвления, синтаксис перечисления для получения формы приращения. Я был очень удивлен, обнаружив, что он :был в объеме даже NoImplicitPreludeбез импорта.
Бен


7

Python 2 от Wheat Wizard (четвертая итерация)

import sys
if set("".join(open(__file__).read().split('\n')[4:]))-set(' &)(,.:[]a`cdfijmonrt~'):sys.setrecursionlimit(1)
for m in sys.modules:sys.modules[m]=None
del sys;f=lambda\
c,d:(`int([]in[])`[:[]in[]]).join([((c)and`dict([((int([]in[])),(int([]in[])))])`[(int([]in[[]])):][(int([]in[[]]))].join([`dict([((int([]in[])),(int([]in[])))])`[(int([]in[]))],`dict([((int([]in[])),c)])`[(int([]in[[]])):][(int([]in[[]])):][(int([]in[[]])):][(int([]in[[]])):]])or`int([]in[])`[:[]in[]]).format((int([]in[]))),((d)and`dict([((int([]in[])),(int([]in[])))])`[(int([]in[[]])):][(int([]in[[]]))].join([`dict([((int([]in[])),(int([]in[])))])`[(int([]in[]))],`dict([((int([]in[])),d)])`[(int([]in[[]])):][(int([]in[[]])):][(int([]in[[]])):][(int([]in[[]])):]])or`int([]in[])`[:[]in[]]).format((int([]in[]))),`(int([]in[]))`]).rfind(`(int([]in[]))`)

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

Никаких эксплойтов, только функция для добавления с использованием только символов ' &)(,.:[]a`cdfijmonrt~', как задумано (на самом деле только '(),.:[]`acdfijmnort').

Я не пытался сделать это коротким; Я только что написал подвыражения для промежуточных значений, таких как 0, а также пустые строки и подставленные в них строки.

def f(c,d):
	FALSE = []in[]
	TRUE = []in[[]]
	ZERO = int([]in[])
	ONE = int(TRUE)
	EMPTY = `int([]in[])`[:[]in[]]
	ZERO_STR = `ZERO`
	ONE_STR = `ONE`

	ZERO_DICT = dict([(ZERO,ZERO)])
	ZERO_DICT_STR = `ZERO_DICT`

	OPEN_BRACE = ZERO_DICT_STR[ZERO]
	COLON = ZERO_DICT_STR[ONE:][ONE]
	CLOSE_BRACE = ZERO_DICT_STR[ONE:][ONE:][ONE:][ONE:][ONE]

	C_STR = `c`
	D_STR = `d`

	FORMAT_STR_C = ''.join([OPEN_BRACE, ZERO_STR, COLON, C_STR, CLOSE_BRACE])
	FORMAT_STR_D = ''.join([OPEN_BRACE, ZERO_STR, COLON, D_STR, CLOSE_BRACE])

	LENGTH_C_STR = c and FORMAT_STR_C.format(ONE_STR) or EMPTY
	LENGTH_D_STR = d and FORMAT_STR_D.format(ONE_STR) or EMPTY

	TOTAL_STR = EMPTY.join([LENGTH_C_STR, LENGTH_D_STR, ZERO_STR])
	RESULT = TOTAL_STR.find(ZERO_STR)

	return RESULT

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

Основная идея заключается в том, что формат строки '{0:5}'.format('1')дополняет число от нуля до длины 5подобия '1 '. Путем объединения двух таких строк ''.join, сумма их длины равна сумме входных чисел. Затем мы добавляем a 0до конца и вызываем .find()конечную позицию, которая является суммой.

Строка '{0:5}'для форматирования создается путем извлечения {:}символов из строковых реплик словарей, созданных с помощью dict. Строка repr каждого последующего слагаемого размещается там, где будет 5. Я хотел использовать диктовку, подобную {0:5}самой себе, но его репр содержит пробел, который испортил его.

Входы 0 запутывают процесс, потому что строка sub имеет минимальную длину 1. У нас есть те, у которых есть and/orпустая строка в этом случае.


1
Это сильно отличается от того, что я намеревался, я хотел бы увидеть объяснение.
Пшеничный волшебник

Вы можете играть в гольф все ваши int([]in[])просто и int()как выход будет 0.
Значение Ink


5

16-битная сборка в реальном времени x86, автор Joshua

    int  0x3                  ; <---  this is the "robber" portion

    ; -- begin code to print numbers in real-mode asm using ROM BIOS video interrupts --
    add  dx, cx               ; add input values together
    mov  ax, dx               ; move result into AX
    push WORD 0xB800
    pop  ds                   ; DS == starting address of text-mode video buffer
    xor  cx, cx               ; digit counter
    xor  di, di               ; position counter
    mov  bx, 0xA              ; divisor

    test ax, ax               ; is number negative?
    jns  .GetDigits
    neg  ax                   ; convert negative number to positive
    mov  WORD ds:[di], 0x4F2D ; output leading negative sign, in white-on-red
    add  di, 2                ; increment position counter

.GetDigits:
    xor  dx, dx
    div  bx                   ; divide DX:AX by 10 (AX == quotient, DX == remainder)
    push dx                   ; push digit onto stack
    inc  cx                   ; increment digit counter
    test ax, ax
    jnz  .GetDigits           ; keep looping until we've got 'em all

.PrintDigits:
    pop  dx                   ; get digit off of stack
    dec  cx                   ; decrement digit counter
    mov  dh, 0x4F             ; high byte: color attribute (white-on-red)
    add  dl, 0x30             ; low  byte: convert to ASCII
    mov  WORD ds:[di], dx     ; output digit
    add  di, 2                ; increment position counter
    test cx, cx
    jnz  .PrintDigits         ; keep looping until we've printed 'em all

    cli
    hlt

снимок экрана с отладочным дампом кода вместе с выводом в верхнем левом углу

Объяснение:

«Обрыв», введенный кодом Джошуа, - это установка флага ловушки (TF), который переводит ЦП в одношаговый режим. Это означает, что одновременно будет выполняться только одна инструкция, прежде чем процессор остановится (перехватит) с прерыванием типа 1. Это то, что позволяет отладчикам реализовывать пошаговый код, что очень удобно, но настоящая PITA, если вы хотите запустить код вне контекста отладчика!

Это следующий раздел кода, который включает флаг прерывания:

pushf               ; push the FLAGS register onto the top of the stack
mov bp, sp          ; load the pointer to the top of the stack into BP
or word [bp], 256   ; bitwise-OR the WORD at the top of the stack (the copy of FLAGS)
                    ;  with 0x100, which turns on bit 8 (TF)
popf                ; pop the modified flags back off the stack into FLAGS

Реализация флага trap-сообщения означает, что у нас есть шанс выполнить ровно одну инструкцию до того, как процессор перехватит ловушку - это та, которая приходит сразу после POPFhere. Итак, нам нужно сделать это один счет.

Уловка - INT 3инструкция, которая вызывает прерывание номер 3. Есть две причины, почему это работает, чтобы "разорвать" код:

  1. Флаг прерывания сбрасывается в обработчиках прерываний. Это всего лишь часть дизайна Intel, но, по-видимому, это было сделано по причинам здравого смысла. Помните , что реализация флага ловушки является то , что прерывание типа 1 вызывается после выполнения каждой команды, так что если TF не был очищен, INT 1будет сам инициировать прерывание, было бы перебивает весь путь вниз. Кроме того, наличие четких прерываний TF просто облегчает отладку кода, подобно IDE, которая автоматически переходит к вызовам библиотечных функций.

  2. Способ прерывания работы по сути такой же, как и дальний CALL. Они вызывают обработчик прерывания, адрес которого хранится в соответствующей позиции в глобальной таблице векторов прерываний. Поскольку эта таблица начинается с адреса 0x0000:0000и хранится в 4-байтовом segment:offsetформате, вычислить адрес так же просто, как умножить 4 на вектор / номер прерывания. В этом случае мы вызываем прерывание 3, так что это будет 4 × 3 = 12.

    ... и вы заметите, что Джошуа задумчиво настроил это для нас. До включения флага ловушки он имеет следующий код:

    mov  di, 12
    mov  [di], si
    mov  [di + 2], bp
    

    который устанавливает 0x0000:000C(обработчик прерывания INT 3) в BP:SI. Это означает, что всякий раз, когда INT 3вызывается, он помещает регистр FLAGS в стек, за которым следует адрес возврата, а затем переходит к нему BP:SI, что позволяет нам снова начать выполнение кода в контексте, где флаг прерывания отключен.

Это все вниз после INT 3. Все, что нам нужно сделать, это сложить вместе два числа и напечатать результат. За исключением того, что на ассемблере это не так просто, как на других языках, так что именно на этом тратится основная часть кода.

Джошуа позволяет грабитель указать любой механизм ввода / вывода (ов) он хочет , так что я беру упрощенный подход в предположении , что значения передаются в DXи CXрегистрах. Это разумно, поскольку они нигде не засорены его «прологовым» кодом.

Вывод выполняется путем сохранения байтов ASCII непосредственно в видеопамять. Видеобуфер начинается 0xB800:0000с текстового режима CGA, EGA и / или VGA, поэтому мы начинаем печать там. Формат: символ в младшем байте и атрибут цвета в старшем байте. Это означает, что каждый символ имеет смещение в 2 байта. Мы просто перебираем каждую из цифр в номере (base-10), конвертируем их в ASCII и печатаем их по одному на экран. Да, это много кода. Там нет библиотечных функций, которые помогут нам в ассемблере. Это почти наверняка можно оптимизировать дальше, но я устал работать над этим ...

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


Я озадачен; Я не могу понять, как это проходит инструкцию hlt в BP: SP + 1.
Джошуа

@ Джошуа Хм, это хорошая мысль. Я даже не думал об этом. Проходя по коду в Debug, я выполняю INT 3и сразу же возвращаюсь к следующей инструкции, поэтому я просто пошел с ней. Может быть, это как-то связано с моей средой тестирования? CLIбудет отключать только аппаратные прерывания, но даже если он HLTпройдет, вы можете подумать, что он провалится и выполнит код lсразу после этого.
Коди Грей,

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

Я тоже тестировал без единого шага. Нет разницы. Это последняя версия FreeDOS в VM Virtualbox. У меня есть настоящее аппаратное обеспечение, но я не хотел его включать. @ Джошуа
Коди Грей,

Ну, вы явно взломали это тогда. Может быть, вы нашли способ поднять этот NMI.
Джошуа


4

Python 3 , 2 - й вызов ppperry

Вау, это было весело! Мне понравилось это решать.

Редактировать: ОК, я исправил это. Кажется, что классы в списке подклассов в TIO отличались от индекса, отличного от моего компьютера, поэтому я заставил их работать для обоих и добавил TIO.

import sys
for mod in sys.modules.values():mod.__dict__.clear()
1+1

# My code begins here
str = "Hello!".__class__
int = (37).__class__
object = str.__base__

def find_subclass(superclass, name):
	for cls in superclass.__subclasses__():
		if cls.__name__ == name:
			return cls

_io_IOBase      = find_subclass(object, '_IOBase')        # <class '_io._IOBase'>
_io_RawIOBase   = find_subclass(_io_IOBase, '_RawIOBase') # <class '_io._RawIOBase'>
_ioFileIO       = find_subclass(_io_RawIOBase, 'FileIO')  # <class '_io.FileIO'>
stdout = _ioFileIO('stdout', mode='w', opener=lambda name,flags: 1) # FD for stdout is 1
stdin  = _ioFileIO('stdin',  mode='r', opener=lambda name,flags: 0) # FD for stdin is 0
nums = str(stdin.read(), encoding='utf-8').split()
stdout.write(str(int(nums[0]) + int(nums[1])).encode('utf-8') + b'\n')
stdout.flush()

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


Я получаю ошибку. sys.excepthook is missing?
17

Хм ... у меня работает. Какую настоящую ошибку вы получаете? (Это происходит потому, что код ppperry уничтожил почти все, включая знание того, как показывать исключения, и это так sys.excepthook, но где-то там будет указана реальная причина.)
zbw

Неважно, настоящая ошибка IndexError('list index out of range',). Это на линии с определением _io_RawIOBase.
Rɪᴋᴇʀ

Проблема в том, что порядок подклассов не фиксирован. _io_IOBase = [cls for cls in object.__subclasses__() if cls.__name__ == '_IOBase'][0]должен работать везде.
Деннис

@ Деннис Да, я понял это и только исправил это. Теперь он работает на TIO!
zbw

4

Haskell от zbw

{-#OPTIONS_GHC -fth -w#-}
module M where

import Language.Haskell.TH.Syntax
import System.IO.Unsafe

a = $( runIO $ TupE[] <$
              do x <- readLn :: IO Integer
                 y <- readLn
                 print $ x + y )

Не можете запустить код во время выполнения? Запустите его во время компиляции!

Это было очень весело, я не знал шаблона haskell до этого испытания.


3

Желе по гипер нейтрино


+

Супер просто. Новая строка приводит к тому, что первая ссылка не вызывается.

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


Вы также можете придерживаться правила отсутствия новой строки, как это
Джонатан Аллан

Да, я думал, что это будет слишком легко.
HyperNeutrino

3

Python 2 от Wheat Wizard

import sys
c="".join(open(__file__).read().split('\n')[4:])
if set(c)-set(' &)(,.:[]a`cdfijmonrt~')or"import"in c:sys.setrecursionlimit(1)
sys.modules['sys'],sys.modules['os']=None,None;del sys;f=lambda\
a,b:a+b
__import__('sysconfig').__dict__['os'].__dict__['sys'].setrecursionlimit(1000)
print(f(1,2))

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


Это оказывается сложнее, чем я думал.
Пшеничный волшебник

3

Java от LordFarquaad

Блокировка доступа к объектам на исходном уровне была действительно умной (и раздражающей при тестировании), молодец!

public class java {
  public static void main(String[] s) {
    //there is no executable code in snippet one.
    //your code here.
    try {
      ClassLoader cl = ClassLoader.getSystemClassLoader();
      Object in = cl.loadClass("java.lang.System").getDeclaredField("in").get(null);
      Object out = cl.loadClass("java.lang.System").getDeclaredField("out").get(null);
      Object scanner = cl.loadClass("java.util.Scanner").getConstructor(cl.loadClass("java.io.InputStream")).newInstance(in);
      int i = (Integer)cl.loadClass("java.util.Scanner").getMethod("nextInt").invoke(scanner);
      int j = (Integer)cl.loadClass("java.util.Scanner").getMethod("nextInt").invoke(scanner);
      cl.loadClass("java.io.PrintStream").getMethod("println", Object.class).invoke(out, i+j);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  class Class {}
  class Method {}
  class System {}
  class FileDescriptor {}
  class Logger {}
  class Runtime {}
  class Scanner {}
}

Ницца! Что, если ClassLoaderбы был в тени?
Якоб

1
@JakobCornell "".getClass().getClassLoader(). Затенение обычно является только проблемой, о которой вам нужно подумать один раз, и тогда все в порядке. Вы могли бы даже тень Object, я все еще смогу решить это. Хорошо, вы могли бы заставить меня в 1kb решение, но это возможно.
Оливье Грегуар


3

Информ 7, Илмари Каронен

Грубое злоупотребление двусмысленными существительными ... Мой код начинается с factory is a room. Предыдущая строка - это код полицейского. Напечатайте, add 1 and 1чтобы получить 2, например.

For reading a command: Rule fails

factory is a room.
The adder one is a thing. The adder two is a thing. The adder one is in factory. The adder two is in factory.
Before reading a command: change the text of the player's command to "examine adder"

For printing a parser error: 
    if the player's command includes "add [number] ":
        let N be the number understood;
        if the player's command includes "and [number]":
            say the number understood plus N;

2

Ява, Роман Греф

public class Main {
    public static void main(String... args){
        System.setOut(null);
        System.setErr(null);

        System.setOut(new java.io.PrintStream(new java.io.FileOutputStream(java.io.FileDescriptor.out)));
        System.setErr(new java.io.PrintStream(new java.io.FileOutputStream(java.io.FileDescriptor.err)));
        System.out.println("This");
        System.err.println("works");
    }
}

Устанавливается stdoutи stderrвозвращается к своим начальным значениям.

Я считаю, что я могу использовать полное имя вместо импорта, если я ошибаюсь, поправьте меня (это мой первый пост здесь). Возможно, это можно сделать и с помощью рефлексии.

Изменить: вот рефлексивное решение, используя только java.lang.reflect.*:

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class Test {
    public static void main(String... args) {
        System.setOut(null);
        System.setErr(null);

        try {
            Class<?> psClass = Class.forName("java.io.PrintStream");
            Class<?> fsClass = Class.forName("java.io.FileOutputStream");
            Class<?> osClass = Class.forName("java.io.OutputStream");
            Class<?> fdClass = Class.forName("java.io.FileDescriptor");
            Class<System> sClass = System.class;
            Constructor psCtor = psClass.getConstructor(osClass);
            Constructor fsCtor = fsClass.getConstructor(fdClass);

            Field modifiersField = Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);

            Object sout = psCtor.newInstance(fsCtor.newInstance(fdClass.getDeclaredField("out").get(null)));
            Field outField = sClass.getDeclaredField("out");
            modifiersField.setInt(outField, outField.getModifiers() & ~Modifier.FINAL);
            outField.set(null, sout);

            Object serr = psCtor.newInstance(fsCtor.newInstance(fdClass.getDeclaredField("err").get(null)));
            Field errField = sClass.getDeclaredField("err");
            modifiersField.setInt(errField, outField.getModifiers() & ~Modifier.FINAL);
            errField.set(null, serr);

            System.out.println("This");
            System.err.println("works");
        } catch (Exception ignore) {
        }
    }
}

Да, stdin, stdoutи stderrхранятся в другом месте! Вам даже не нужно использовать setOutи, setErrкак вы можете просто использовать PrintStreamнапрямую.
Оливье Грегуар

Добавлено рефлексивное решение, так как я чувствую, что это было то, что изначально ожидалось
Мойра

2

JavaScript от Даниэль Франклин

location="data:text/html;base64,PHNjcmlwdD5jb25zb2xlLmxvZygxKnByb21wdCgpKzEqcHJvbXB0KCkpPC9zY3JpcHQ+"

Это может считаться немного обманчивым решением, но оно работает для меня на Chromium 59 / Linux, даже если я также получаю предупреждение:

В следующих версиях навигация по верхнему фрейму, инициированному контентом, будет блокировать данные: URL-адреса. Для получения дополнительной информации см. Https://goo.gl/BaZAea .

Ps. Вот еще один треск, на этот раз без предупреждений:

Node.prototype.removeChild=function(){}
document.body.innerHTML='<iframe src="data:text/html;base64,PHNjcmlwdD5jb25zb2xlLmxvZygxKnByb21wdCgpKzEqcHJvbXB0KCkpPC9zY3JpcHQ+"/>'

Я думаю, что prompt()- -prompt()сохраняет два байта
Мари

2

Java 8 Оливье Грегуар

Чрезвычайно многословная трещина для чрезвычайно многословного испытания. :) Боль косвенной работы с классами, которые вы не можете назвать, ощутима.

    try {
      Class loader = Class.class.getMethod("getClassLoader").getReturnType();
      Object sysLoader = loader.getMethod("getSystemClassLoader").invoke(null);
      Class integer = (Class) loader.getMethod("loadClass", String.class).invoke(sysLoader, "java.lang.Integer");
      Class system  = (Class) loader.getMethod("loadClass", String.class).invoke(sysLoader, "java.lang.System");
      Class filein  = (Class) loader.getMethod("loadClass", String.class).invoke(sysLoader, "java.io.FileInputStream");

      InputStream cmd = (InputStream) filein.getConstructor(String.class).newInstance("/proc/self/cmdline");
      byte[] buf = new byte[65536];
      int len = cmd.read(buf);
      String[] args = new String(buf, 0, len).split("\0");
      
      int a = (int) integer.getMethod("parseInt", String.class).invoke(null, args[args.length-2]);
      int b = (int) integer.getMethod("parseInt", String.class).invoke(null, args[args.length-1]);

      Object out = system.getField("out").get(null);
      out.getClass().getMethod("println", String.class).invoke(out, ""+(a+b));
    } catch (Exception e) {
      throw new Error(e);
    }
  }
}
class ClassLoader {
  public static ClassLoader getSystemClassLoader() { return new ClassLoader(); }
  public ClassLoader loadClass(String s) { return this; }
  public ClassLoader getDeclaredField(String s) { return this; }
  public ClassLoader getMethod(String s) { return this; }
  public ClassLoader getMethod(String s, Class c) { return this; }
  public InputStream get (Object o) { return new FakeInputStream(); }
  public void invoke(Object o, SecurityManager sm) {}
}
class FakeInputStream extends InputStream {
  public int read() {
    return -1;

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

Ps. Вот моя более ранняя попытка, написанная до того, как Оливье пояснил, что ввод должен был осуществляться через аргументы командной строки. В отличие от рассмотренного выше трека, этот не специфичен для Linux.

    try {
      Class loader = Class.class.getMethod("getClassLoader").getReturnType();
      Object sysLoader = loader.getMethod("getSystemClassLoader").invoke(null);
      Class integer = (Class) loader.getMethod("loadClass", String.class).invoke(sysLoader, "java.lang.Integer");
      Class system  = (Class) loader.getMethod("loadClass", String.class).invoke(sysLoader, "java.lang.System");
      Class scanner = (Class) loader.getMethod("loadClass", String.class).invoke(sysLoader, "java.util.Scanner");

      InputStream in = (InputStream) system.getField("in").get(null);
      Object scanIn = scanner.getConstructor(InputStream.class).newInstance(in);

      int a = (int) scanner.getMethod("nextInt").invoke(scanIn);
      int b = (int) scanner.getMethod("nextInt").invoke(scanIn);

      Object out = system.getField("out").get(null);
      out.getClass().getMethod("println", String.class).invoke(out, ""+(a+b));
    } catch (Exception e) {
      throw new Error(e);
    }
  }
}
class ClassLoader {
  public static ClassLoader getSystemClassLoader() { return new ClassLoader(); }
  public ClassLoader loadClass(String s) { return this; }
  public ClassLoader getDeclaredField(String s) { return this; }
  public ClassLoader getMethod(String s) { return this; }
  public ClassLoader getMethod(String s, Class c) { return this; }
  public InputStream get (Object o) { return new FakeInputStream(); }
  public void invoke(Object o, SecurityManager sm) {}
}
class FakeInputStream extends InputStream {
  public int read() {
    return -1;

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


Если вы готовы, вот мой новый вызов .
Оливье Грегуар,

Просто для того, чтобы написать это здесь: поскольку я не имею права говорить «Понятно! Он работает только в одной системе», этот ответ не полностью решает проблему, потому что он работает только в Linux.
Оливье Грегуар,

@ OlivierGrégoire: FWIW, я придумал альтернативное решение String[] args = ((String) system.getMethod("getProperty", String.class).invoke(null, "sun.java.command")).split(" ");, которое не зависит от Linux, но использует то, что кажется недокументированным свойством, установленным некоторыми JVM.
Ильмари

Это все еще не портативно. Это не будет работать на IBM Java, например. Тем не менее, это хорошая идея! :)
Оливье Грегуар

2

C # (.NET Core) разнагул

Я предполагаю, что это не было намеченным решением.

int a;
int b;

using (var f = new System.IO.FileStream("/dev/stdin", System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
using (var fs = new System.IO.StreamReader(f))
{
a = int.Parse(fs.ReadLine());
b = int.Parse(fs.ReadLine());
}
}
using (var f = new System.IO.FileStream("/dev/stdout", System.IO.FileMode.Open, System.IO.FileAccess.Write))
{
using (var fs = new System.IO.StreamWriter(f))
{
fs.WriteLine((a + b).ToString());
}
}

Хороший трюк с /dev/std*этим. Первоначально я стремился к подобному подходу, но не мог найти простой способ открыть потоки для stdin / out без доступа к System.Console, поэтому вместо этого я выбрал рефлексию. Конечно, ваше решение предположительно работает только в Linux и других системах Unixish с соответствующими /devзаписями, но Разнагул не сказал, что оно должно работать в Windows. И это работает на TIO.
Ильмари

@IlmariKaronen: Действительно; и мой план, если бы это была Windows, потерпела бы неудачу на TIO.
Джошуа

1

Java, по racer290

Это было довольно простое упущение, что staticинициализаторы вызываются перед mainметодом. Это была хорошая попытка: throw new Error()сначала я был встревожен , но в конце концов нашел путь;)

public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException, NoSuchMethodException {

    try {

        System.class.getField("in").set(null, null);
        System.class.getField("out").set(null, null);
        System.class.getField("err").set(null, null);

        System.class.getMethod("getSecurityManager", new Class[0]).setAccessible(false);

        File.class.getField("fs").set(null, null);

        for (Method m : Class.class.getMethods()) {

            m.setAccessible(false);

        }

        SecurityManager mngr = new SecurityManager() {

            @Override
            public void checkPermission(Permission p) {

                throw new Error("Muahaha!");

            }

            @Override
            public void checkLink(String s) {

                throw new Error("Not this way, my friend!");

            }

        };

        System.setSecurityManager(mngr);

    } catch (Throwable t) {

    }
    // My code here, I guess...
} static {
  java.util.Scanner s = new java.util.Scanner(System.in);
  System.out.println(s.nextInt()+s.nextInt());

    // End of my code
}

System.out.println("Hello World!");Не добавляет два целых числа? .. " 2. Фрагмент кода, который принимает два числа в качестве входных данных, складывает их вместе и выводит их сумму. Этот фрагмент должен работать правильно даже после запуска первого фрагмента. Когда два фрагмента в сочетании друг с другом, они должны сформировать полную программу , которая добавляет два числа, или определить функцию , которая добавляет два числа Этот фрагмент, вероятно , полагаться на неясного поведение, и трудно найти.. "
Кевин Cruijssen

@KevinCruijssen Что я могу сказать? Если копы не делают свою работу, зачем мне их? : P
Оливье Грегуар

1
@KevinCruijssen Там я добавил туда дополнение.
Оливье Грегуар

@ OlivierGrégoire весь смысл состоит в том, чтобы предотвратить добавление чисел, будь то удаление возможности ввода, добавления или вывода.
Стивен

@ StepHen Да, я понял это немного позже. Проверьте мои 3 другие трещины, чтобы увидеть, что я наконец понял это;)
Оливье Грегуар

1

Java от Кевина Круйссена

Хорошо построен. Много кода, чтобы заставить любого должным образом задуматься, как решить эту проблему. Я полагаю, что «поставить свой код потом» было большим, большим намеком.

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileDescriptor;
import java.io.FilePermission;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class Main {

  // Put everything in a static block so it is run before the static main method 
  // and any trailing (static) initializer-blocks:
  static {
    try {
      initializing();
    } catch (final Exception e) {
    }
  }

  static void initializing() throws Exception {
    // Overwrite System.out, System.err and System.in:
    System.setOut(new PrintStream(new ByteArrayOutputStream()));
    System.setErr(new PrintStream(new ByteArrayOutputStream()));
    System.setIn(new ByteArrayInputStream(new byte[0]));

    // Enable reflection for System.out, System.err and System.in:
    final Field modifiersField = Field.class.getDeclaredField("modifiers");
    modifiersField.setAccessible(true);
    final Class<?> fdClass = java.io.FileDescriptor.class;
    final Field outField = fdClass.getDeclaredField("out");
    outField.setAccessible(true);
    modifiersField.setInt(outField, outField.getModifiers() & ~Modifier.FINAL);
    final Field errField = fdClass.getDeclaredField("err");
    errField.setAccessible(true);
    modifiersField.setInt(errField, errField.getModifiers() & ~Modifier.FINAL);
    final Field inField = fdClass.getDeclaredField("in");
    inField.setAccessible(true);
    modifiersField.setInt(inField, inField.getModifiers() & ~Modifier.FINAL);

    // Replace existing System.out FileDescriptor with a new (useless) one:
    outField.set(null, new FileDescriptor());
    // Replace existing System.err FileDescriptor with a new (useless) one:
    errField.set(null, new FileDescriptor());
    // Replace existing System.in FileDescriptor with a new (useless) one:
    inField.set(null, new FileDescriptor());

    // Disable reflection for System.out, System.err, System.in again:
    modifiersField.setInt(outField, outField.getModifiers() & ~Modifier.FINAL);
    modifiersField.setInt(errField, errField.getModifiers() & ~Modifier.FINAL);
    modifiersField.setInt(inField, inField.getModifiers() & ~Modifier.FINAL);
    inField.setAccessible(false);
    errField.setAccessible(false);
    outField.setAccessible(false);
    modifiersField.setAccessible(false);

    // Overwrite the SecurityManager:
    System.setSecurityManager(new SecurityManager() {

      private boolean exitAllowed = false;

      @Override
      public void checkExec(final String cmd) {
        throw new SecurityException();
      }

      @Override
      public void checkPermission(final java.security.Permission perm) {
        final String name = perm.getName();
        // You're not allowed to read/write files:
        if (name.equals("setIO") || name.equals("writeFileDescriptor")
            || name.equals("readFileDescriptor")
            || ((perm instanceof FilePermission) && name.startsWith("/proc/self/fd/"))) {
          throw new SecurityException();
        }
        // You're not allowed to overwrite the Security settings:
        if (name.equals("setSecurityManager") || name.equals("suppressAccessChecks")) {
          throw new SecurityException();
        }
        // You're not allowed to use reflection anymore:
        if (name.equals("getModifiers") || name.equals("get") || name.equals("set")
            || name.equals("setBoolean") || name.equals("setByte")
            || name.equals("setChar") || name.equals("setShort") || name.equals("setInt")
            || name.equals("setLong") || name.equals("setFloat") || name.equals("setDouble")
            || name.equals("setFieldAccessor") || name.equals("setFieldAccessor")) {
          throw new SecurityException();
        }
        // When you try to leave the current VM it will stop the program:
        if (name.startsWith("exitVM") && !this.exitAllowed) {
          this.exitAllowed = true;
          System.exit(0);
        }

        // You know what, nothing is allowed!
        throw new SecurityException("Mhuahahahaha!");
      }
    });
  }

  public static void main(String[] args) {
    // Overwritting all given arguments:
    args = new String[0];

    // Exit the program before you can do anything!
    System.exit(0);
  }
}

class System {
  static void exit(int n) {}
  static void setSecurityManager(SecurityManager sm) {
    java.util.Scanner scanner =new java.util.Scanner(java.lang.System.in);
    java.lang.System.out.println(scanner.nextInt() + scanner.nextInt());
  }
  static void setIn(Object o) {}
  static void setOut(Object o) {}
  static void setErr(Object o) {}
}

Попробуй это здесь.


Это было быстро .. Это было действительно мое точное решение! Отлично сработано. :) РЕДАКТИРОВАТЬ: взял на себя смелость добавить ссылку TIO, если вы не возражаете.
Кевин Круйссен

Ну, на самом деле я работал над этой идеей с задачей гонщика 290, когда вы опубликовали свою. И нет, я не против.
Оливье Грегуар


1

cQuents , Step Hen , 3 байта

+BC

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

Много говорил с Step Hen, чтобы выяснить, как, черт возьми, работает его странный язык, но вкратце:

Его код был #|1,1:A. #|1,1является вводом по умолчанию, означающим, что любой ввод данных программе добавляется 2 1. (То есть, если вы передаете 47 и 53, ваш ввод [47, 53, 1, 1].

:просто устанавливает режим, который будет выводить nth-й элемент в последовательности, если nон установлен, и в противном случае выводит всю последовательность.

Наконец Aполучает первый вход.

Поскольку у нас есть 4 входа [47, 53, 1, 1], добавление BCв конец также извлечет 2-й и 3-й входы, а 4-й ввод неявно становится n.

Поскольку наша последовательность ABCразбирается алгебраически, то есть становится A*B*C. Мы не хотим этого, но если мы вставим a +между A и B, оно становится A+B*C, где Aи Bявляются нашими входами, и Cравно 1.


how the hell his weird language worksвозможно, как только я закончу это, это может иметь некоторый смысл
Стивен

@ StepHen не поймите меня неправильно, это аккуратный язык, но странный, как ад
Skidsdev

1

C # (.NET Core) разнагул

var console = typeof(System.ConsoleCancelEventArgs).Assembly.GetType("System.Console");
var readLine = console.GetMethod("ReadLine");
var writeLine = console.GetMethod("WriteLine", new Type[] { typeof(int) });
int a = Int32.Parse((string) readLine.Invoke(null, null));
int b = Int32.Parse((string) readLine.Invoke(null, null));
writeLine.Invoke(null, new object[] {a+b});

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

Это, вероятно, заняло бы меньше времени, если бы я действительно знал C #. Однако, с некоторым просмотром документации и небольшой помощью от Джона Скита , мне удалось собрать кое-что, что работает.


1

Vim Challenge от @DJMcMayhem

Прошло много времени с тех пор, как я не смог выйти из vim , вот мое решение (обратите внимание, что это намного больше, чем 23байты - так что, вероятно, это не предполагаемое решение):

i
echo "
12
39
"|awk '{s'$(python -c "print(''.join([chr(43),chr(61)]))")'$1} END {print s}'<Esc>vgg!bash

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

Идея состоит в том , чтобы просто трубы два целых чисел с awkпомощью bash, так =и +отключенный мне пришлось использовать небольшие обходным. awkЛиния расширяется:

"|awk '{s'+='} END {print s}

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

Вот предлагаемое исправление @DJMcMayhem: попробуйте онлайн!


Я думаю, не думаю, что вы можете сделать [insert your number here]в режиме вставки. Вместо этого он уже находится в буфере. Но вы можете обойти это Oecho "<esc>Go"|awk..., так что я думаю, что это имеет значение. Красиво сделано! Это не та кряка, которую я имел в виду (я надеялся на чистый ответ vim), поэтому я, вероятно, опубликую новый ответ, который исправляет внешние команды и !.
DJMcMayhem

1
Вот пример, который правильно вводит данные: Попробуйте онлайн!
DJMcMayhem

Да, я не был уверен насчет ввода. Но обходной путь действительно будет легким. Я отредактирую официальным способом.
მოიმო

Кстати, мой пропатченный подход здесь: codegolf.stackexchange.com/a/133441/31716
DJMcMayhem

1

Java 7 от Poke

  }
  public static void main(java.lang.String[]a) throws Exception {
    int x = Integer.parseInt(a[0]);
    int y = Integer.parseInt(a[1]);
    java.lang.System.out.println(x+y);
  }
}
class String {
}
class System {
  public static java.io.InputStream in = new java.io.ByteArrayInputStream(new byte[0]), out = in, err = in;
  public static void setProperties (Object o) {

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

Никаких специфических трюков для Linux не требуется, просто маскировка неквалифицированных Stringи Systemимен классов. Это, вероятно, не предполагаемое решение, но оно работает.



1

RProgN2 от @ATaco

"+-/*÷^"{²[[\=};
{"D"=11{‹1D&¬\D›]"D"=}:]1\2\Š1{[\D‹|"D"=};D¬{1"D"=1\2\Š1{[D‹"D"=};}{[}?D}"~"={"d"="g"=g~d&gd~&|}"±"={"H"="I"=11{‹H1&I1&±\H›"H"=I›"I"=H¬¬I¬¬|}:1\2\Š1{[H‹|"H"=};H}"×"={"J"="K"=1{JK&‹JK×"K"=]"J"=}:JK|}"+"=

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

Это далеко не лучший ответ, который я мог бы дать, но он позволяет снова складывать числа. Если бы я на самом деле прошел и сделал правильную обработку стека, я бы, наверное, немного играл в гольф, но на данный момент я доволен ответом.

В оригинальном посте ATaco он фактически просто переназначил все основные арифметические операторы, чтобы уничтожить их входные данные. Чтобы исправить эту проблему, я переопределил, что было добавление в терминах его двоичных операций, что было проблемой, потому что RProgN2 не имеет двоичного оператора отрицания или xor.

Примечание: Если вы хотите проверить ввод, числа с более чем одной цифрой должны быть в форме "XX..." nдля преобразования в фактическое число, так как RProgN2 принимает каждый символ как есть, если это не концепция или строка. Редактировать: @ATaco отметил, что добавление «$» перед многозначным числом будет делать то же самое.

РЕДАКТИРОВАТЬ: Вот логика для моего решения. Как видите, определенно не самый изысканный код, но он работает.

{"D"=11{‹1D&¬\D›]"D"=}:]1\2\Š1{[\D‹|"D"=};D¬{1"D"=1\2\Š1{[D‹"D"=};}{[}?D}"~"= # Defines the ~ operator which negates a number
{"D"=                                                                   }     # Remove the top of the stack and assign D with the popped value
     11                                                                       # Push 2 1's to the stack.  The first is used as a counter, the second if the initial truthy value for the loop
       {             }:                                                       # Start a while loop if the top of the stack (popped) is truthy (removes final falsey value)
        ‹                                                                     # Left shift the counter variable
         1D&¬                                                                 # Push negation of last bit of D
             \                                                                # Swap the counter (index 1) and the negated bit (index 0)
              D›]"D"=                                                         # Push D, right shift it, duplicate the value on the stack, then pop and assign the top to D
                       ]1\                                                    # Duplicate the counter, push 1, and swap the counter to the top of the stack
                          2\Š                                                 # Push 2, swap with the counter, then take the log (log_2(counter))
                             1{         };                                    # Run the for loop "for (i=1;i<=log_2(counter);i+=1)"
                               [\                                             # Pop off i, then swap the original counter with the next bit to append
                                 D‹|"D"=                                      # Left shift D, or it with the next bit, then assign D the new value
                                          D¬                                  # Need to check if D was 0 or not (in the case of 0b11...1~)
                                            {                     }{ }?       # Conditional on the truthiness of not D
                                             1"D"=                            # If D was 0, we assign it as 1, then start to bit shift it up
                                                  1\2\Š1{       };            # Same for loop as earlier since the original counter is still on the top of the stack
                                                         [D‹"D"=              # Pop off i, left shift D, then reassign it
                                                                    [         # Else D was non-zero, so just pop off the counter we've been carrying around
                                                                       D      # Push the final value to the top of the stack as a return
                                                                         "~"= # Assign the function between the {}'s to the character '~'

{"d"="g"=g~d&gd~&|}"±"=                                                       # Defines the ± operator which performs a single bit xor
{"d"="g"=         }                                                           # Assign d and g the first and second values on the stack respectively
         g~d&                                                                 # Push ~g&d to the top of the stack
             gd~&                                                             # Push g&~d to the top of the stack
                 |                                                            # Or the top 2 values giving us (~g&d)|(g&~d)
                   "±"=                                                       # Assign this function to the ± operator

{"H"="I"=11{‹H1&I1&±\H›"H"=I›"I"=H¬¬I¬¬|}:1\2\Š1{[H‹|"H"=};H}"×"=             # Defines the × operator which performs a full number xor
{"H"="I"=                                                   }                 # Store the top 2 stack values in H and I (in that order)
         11{                            }:                                    # Another while loop with the first one being a counter for later, and the second is our truthy value to start the loop
            ‹H1&I1&±                                                          # Left shift the counter, then push the bit xor of H's and I's lowest bit ((H&1)±(I&1) in infix notation)
                    \                                                         # Swap the calculated bit and the counter
                     H›"H"=I›"I"=                                             # Right shift both variables and store the values back in them
                                 H¬¬I¬¬|                                      # Effectively pushing the value (H!=0 | I != 0)
                                          1\2\Š1{        };                   # Same for loop as the ones above
                                                 [H‹|"H"=                     # Pop off the for loop counter, left shift H, or it with the next bit, and reassign
                                                           H                  # Push the final computed xor value to the top of the stack
                                                             "×"=             # Assign this whole function to the × operator

{"J"="K"=1{JK&‹JK×"K"=]"J"=}:JK|}"+"=                                         # Finally, a function redefining addition as the "+" operator
{"J"="K"=                       }                                             # Store the top 2 stack values in J and K respectively
         1{                }:                                                 # An initial truthy value to start the while loop and the loop itself
           JK&‹                                                               # Push (J&K)<<1 to the stack
               JK×                                                            # Compute the full xor of J and K (J^K in Python)
                  "K"=                                                        # Assign K the value of J xor K
                      ]"J"=                                                   # Duplicate (J&K)<<1 and assign 1 copy to J, leaving (J&K)<<1 as our while check (while ((J&K)<<1))
                             JK|                                              # Finally push the value J|K to the stack to get the addition
                                 "+"=                                         # Assign this function to the "+" operator, restoring it

Предоставление $ перед строкой чисел также группирует его как одно число, например 56$46$12, подтолкнет числа 5, 6, 46 и 12. Я
опубликую

Не знал этого. Я просто просмотрел твои призывы, чтобы выяснить, что это было.
Арнольд Палмер

Я мог бы действительно написать некоторую документацию из-за этой проблемы.
ATaco

Это было бы замечательно. Мне удалось найти список команд для RProgN, но я его потерял ... И это очень помогло, поскольку все функции разные. Я должен был изучить твои функции через твою старую страницу учебника RProgN и твои вызываемые классы. Было весело поиграть, даже если не сразу было понятно, как все работает.
Арнольд Палмер

1

JavaScript (Node.js) от jrich , 298 байт

Я чувствую, что это не предполагаемое решение, но, если оно, хорошо, я потратил некоторое время, пытаясь выяснить, как получить имя объявленной функции! :)

var p=process,f;(_=>{var w=p.stdout.write,n='f'+(Math.random()*1e7|0),l=1
f=p.stdout.write=a=>eval(`(function ${n}(a){while(l&&((typeof a)[0]!='s'||'f'+a!=n));a=l?l="":a;w.apply(p.stdout,arguments);})`)(a)})();
process.stderr.write.call(process.stdout,''+((0|process.argv[2])+(0|process.argv[3])));

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


1
Не предполагаемое решение, но очень умное! Хороший крэк +1
рождения

@jrich Да, я подумал, не стесняйся исправить это, я обязательно попробую другое решение!
Дом Гастингс

упс ... слишком поздно! Я был доволен креативностью вашего решения, хотя!
17
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.