Советы по игре в гольф в GolfScript

35

Что, этот пост еще не существует?

Конечно, GolfScript это сделано для игры в гольф, так что вы могли бы подумать , что никаких конкретных советов не действительно необходимы. Но чтобы в полной мере использовать возможности GolfScript, вам необходимо изучить некоторые неочевидные приемы. Этот пост предназначен для сбора полезных советов и подсказок.

Для начала, вот официальные справочные страницы GolfScript. Вы должны действительно ознакомиться с этим в первую очередь:

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


Ps. Ради вдохновения и личного интереса, вот несколько вопросов, которые я бы бы получить хорошие ответы:

  • Как сделать ограниченную транслитерацию в GolfScript? {FROM?TO=}%работает, если вы можете быть уверены, что все входные данные найдены FROM(или не против того, чтобы все они отображались на последний элемент TO), но все способы, которые я видел для оставления неизмененных значений без изменений, были более или менее полезны.

  • Как лучше всего преобразовать строку в массив кодов ASCII и обратно? Какие операции делают это как побочный эффект? Каков наилучший способ выбросить символы в строке в стек (как это ~делается для массивов)?

Илмари Каронен
источник
Другой вопрос: есть ли хороший способ превратить ... xв ... [x]? Лучшее, что я могу видеть, это [.;].
Питер Тейлор
@Peter: Если xчисло, то []+работает и на один символ короче. И, конечно же, если xв стеке стоит только одно, то просто ]подойдет.
Илмари Каронен
Я хотел бы спросить лучшие способы сделать: минимальное, максимальное и абсолютное значение. Кажется, что все мои решения занимают больше персонажей, чем следовало бы.
Клавдиу
Каков наилучший способ изменить массив по заданному индексу?
user1502040
@ user1502040: ответ ниже. (Если кто-нибудь знает лучший способ, пожалуйста, поделитесь!)
Ilmari Karonen

Ответы:

29

Рациональный / Поплавок / Комплекс

Я столько раз читал, что в GolfScript есть только целые числа, и я начал в это верить. Ну, это не правда.

2-1? # Raise 2 to the power of -1. Result: 0.5
4-1? # Raise 4 to the power of -1. Result: 0.25
+    # Add. Result: 0.75

Выход

3/4

со стандартным интерпретатором GolfScript и

0.75

на веб-сайте GolfScript .

Подобные хаки позволяют разыгрывать в Rational, Float или даже Complex:

{-2.?./*}:rational
{2.-1??./*}:float
{-2.-1??./*}:complex
Деннис
источник
9
OMGWTFHAX о_О !!!
Ильмари Каронен
3
WAT! Уверен, это ошибка в интерпретаторе, но ничего себе
Ручка ручки
3
Линия 82 из самого последнего переводчика: Gint.new(@val**b.val). Похоже, что в Gintконструкторе отсутствует int int ...
primo
10

Отрицание числа

В GolfScript не хватает только встроенного оператора отрицания. Очевидные способы преобразования числа в стеке в его отрицательное значение, например -1*or или 0\-, требуют трех символов. Тем не менее, есть способ сделать это в два:

~)

Это работает, потому что GolfScript использует арифметику дополнения до двух , так что ~ x равно - x −1.

Конечно, вариант (~также работает; Выбор между ними - дело вкуса.

Илмари Каронен
источник
9

Перетасовывать массив

Самый простой способ перемешать массив в GolfScript - это отсортировать его по ключу случайной сортировки. Если вам нужно только грубо перемешать несколько значений, подойдет следующий код:

{;9rand}$

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

Замена 9вышеупомянутого 99таким образом дает достаточно хорошие результаты для списков до десяти элементов, но демонстрирует заметное смещение для более длинных списков.

Следующий код, который использует 9 9 = 387 420 489 возможных значений, подходит для примерно 1000 элементов или около того (и приемлем для примерно до 20 000):

{;9.?rand}$

Для действительно длинных списков добавьте еще 9 для 99 99 ≈ 3,7 × 10 197 значений:

{;99.?rand}$

Тестирование:

Вот распределение первого элемента в 10-элементном списке, перетасованном с использованием различных вариантов, показанных выше, с выборкой из 10 000 испытаний:

  • Вывод 10,{;9rand}$0=показывает очень четкое смещение, с 0вероятностью более чем в три раза оказаться в первой позиции, как 1:

    0 16537 #######################################################
    1 5444  ##################
    2 7510  #########################
    3 8840  #############################
    4 9124  ##############################
    5 12875 ##########################################
    6 9534  ###############################
    7 8203  ###########################
    8 7300  ########################
    9 14633 ################################################
    
  • При этом 10,{;99rand}$0=большая часть предвзятости исчезла, но заметное количество все еще остается:

    0 10441 ##################################
    1 9670  ################################
    2 9773  ################################
    3 9873  ################################
    4 10134 #################################
    5 10352 ##################################
    6 10076 #################################
    7 9757  ################################
    8 9653  ################################
    9 10271 ##################################
    
  • При 10,{;9.?rand}$0=этом выходные данные практически не отличаются от действительно случайной выборки:

    0 9907  #################################
    1 9962  #################################
    2 10141 #################################
    3 10192 #################################
    4 9965  #################################
    5 9971  #################################
    6 9957  #################################
    7 9984  #################################
    8 9927  #################################
    9 9994  #################################
    

Ps. Для действительно плохой перестановки числовых массивов или строк иногда может быть приемлем следующий код:

{rand}$

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

Илмари Каронен
источник
3
Я помню, я однажды скептически сделал математику для парадокса дня рождения после того, как мой брат сказал мне об этом, он был прав :(
ajax333221
8

Чтобы решить конкретный вопрос:

Как лучше всего преобразовать строку в массив кодов ASCII и обратно? Какие операции делают это как побочный эффект? Каков наилучший способ выгрузить символы в строке в стек (как ~ делает для массивов)?

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

'ABC123'{)}%

покинет 'BCD234' в стеке.

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

Каков наилучший способ выбросить символы в строке в стек? {}/

Какой лучший способ преобразовать строку в массив кодов ASCII? [{}/](с обычной оговоркой, что если в стеке больше ничего нет, вы можете пропустить [)

Каков наилучший способ преобразовать массив кодов ASCII в строку? ''+(Обратите внимание, что это также выравнивает массив, например, [65 [66 67] [[[49] 50] 51]]''+дает 'ABC123')

Питер Тейлор
источник
Каков наилучший способ превратить один код ASCII в строку? []+''+? (кажется довольно долго)
Джастин
@ Quincunx, это довольно долго, но я не знаю лучшего способа. Что нужно сделать, это посмотреть, откуда взялся код ASCII и посмотреть, можете ли вы заставить его поступать уже в массиве.
Питер Тейлор
6

Если ваша программа таинственно ломается, проверьте ваши переменные

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

Питер Тейлор
источник
6

Заворачивание верхнего элемента стека в массив

Есть ли хороший способ превратить ... xв ... [x]?

Для полной общности лучшим вариантом является 4 символа. Однако в некоторых особых случаях это можно уменьшить.

1 символ

] работает в особом случае, что x является единственным в стеке.

3 символа

[]+работает в особом случае, который xявляется целым числом.

.,/работает в особом случае, который xявляется истинным массивом или строкой. Например, "AB".,/дает ["AB"]; 3,.,/дает [[0 1 2]]. Впрочем, "".,/и то и [].,/другое дают [].

4 символа

[.;] работает безоговорочно.

Питер Тейлор
источник
6

Каков наилучший способ изменить массив по заданному индексу? - user1502040

Это хороший вопрос. Не существует прямого способа присвоить значение элементу массива в GolfScript, поэтому, так или иначе, вам придется перестраивать весь массив.

Самый короткий общий способ, которым я знаю, чтобы вставить новое значение xпо индексу iв массиве, состоит в том, чтобы разделить массив по указанному индексу и добавить xв первую половину, прежде чем снова соединить их вместе:

  • .i<[x]+\i>+(11 символов) - вставить значение xв массив с индексом (от 0)i

Для того, чтобы заменить значение по индексу iс x, нам нужно просто сократить вторую половину массива на один элемент:

  • .i<[x]+\i)>+(12 символов) - заменить элемент iс индексом (на основе 0) значениемx

Альтернативно, сокращение первой половины вместо этого будет эффективно делать то же самое, но с индексацией на основе 1, которая иногда может быть предпочтительнее:

  • .i(<[x]+\i>+(12 символов) - заменить элемент iс индексом (на основе 1) значениемx

Во всех приведенных выше примерах, если xэто число, квадратные скобки вокруг него могут быть опущены, чтобы сохранить два символа, так как в +любом случае он будет автоматически приведен в массив :

  • .i<x+\i>+(9 символов) - вставьте число xв массив по индексу (от 0)i
  • .i<x+\i)>+(10 символов) - заменить элемент iс индексом (на основе 0) числомx
  • .i(<x+\i>+(10 символов) - заменить элемент iс индексом (на основе 1) числомx

Квадратные скобки также могут быть опущены, если один xили входной «массив» (или оба) на самом деле являются строками, и в этом случае результат также будет приведен к строке (используя обычные правила преобразования массива → строки).


Ps. В особом случае, если мы знаем, что массив содержит элементы между iдвумя и двумя iэлементами, мы можем вставить новый элемент с xиндексом ( на основе 0) iс помощью i/[x]*(6 символов). Что это на самом деле делает, так это разбивает массив на части по не более iэлементов и вставляет xмежду ними. Обратите внимание, что в этом случае скобки необходимы, даже если xэто число.


Pps. Альтернативный подход заключается в использовании динамически именованных переменных. Например,

 'foo' 42 ':x'\+~

назначит значение 'foo'переменной x42, в то время как

 42 'x'\+~

получит это.

Вы можете оптимизировать это далее, пропустив xпрефикс и просто присваивая непосредственно числовым литералам - это совершенно законно в GolfScript и позволяет вам сохранить один символ из кода присваивания и сократить код извлечения до всего `~(или вообще ничего, если индекс постоянен!). Недостатком, конечно, является то, что присвоение числового литерала переопределит значение этого литерала где-либо еще в вашем коде. Однако часто можно избежать использования числовых литералов (или, по крайней мере, ограничить их началом до того, как какой-либо из них будет переназначен), и в этом случае этот трюк вполне подходит.

Илмари Каронен
источник
3
Совершенно не по теме: поздравляю с 10к! :-D
Дверная ручка
1
Если вы знаете, что массив не имеет повторяющихся значений, вы можете заменить значение в индексе iна 9 байтов:.[i=]/[x]*
Мартин Эндер
5

Конечный выход манипуляции

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

]puts

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

{print n print}:puts;

Таким образом, вы можете подавить или манипулировать конечный результат путем переопределения puts, print и / или n(или  если вы чувствуете себя действительно скручены). Вот некоторые примеры:

Подавить финальный перевод строки:

'':n;

(Конечно, вы можете оставить ; если вы не возражаете против лишней пустой строки в стеке.)

Подавить окончательный вывод полностью:

:puts

Это перезаписывает putsвсе, что происходит на вершине стека. Если это то, что вы не хотите выполнять, вы можете использовать, например, 0:puts;вместо этого. Обратите внимание, что это также подавляет p(что определяется как {`puts}:p;), но вы все равно можете использовать printдля вывода, если хотите.

Илмари Каронен
источник
И nothingвы имеете в виду \n?
CalculatorFeline
Если вы не возражаете против завершающей новой строки, вы также можете использовать ];для подавления окончательного вывода.
wastl
5

Я хотел бы спросить лучшие способы сделать: минимальное, максимальное и абсолютное значение. Кажется, что все мои решения занимают больше персонажей, чем следовало бы. - Клаудиу

мин Макс

Чтобы найти наименьшее / наибольшее значение в массиве, просто отсортируйте его и возьмите первый / последний элемент:

  • $0= (3 символа) - минимальный элемент в арри
  • $-1= (4 символа) - максимальный элемент в массиве

Если вы знаете длину массива, и она составляет 10 элементов или меньше, вы можете найти максимум в трех символах, заменив -1 его индексом последнего элемента.

Если у вас есть значения в стеке, вы можете сначала собрать их в массив. Для этого иногда полезный трюк заключается в том, [\]что два верхних элемента стека [@]собираются в массив, а три верхних. Таким образом, мы получаем:

  • [\]$0= (6 символов) - минимум два значения в стеке
  • [@]$0= (6 символов) - минимум три значения в стеке
  • [\]$1= (6 символов) - максимум два значения в стеке
  • [@]$2= (6 символов) - максимум три значения в стеке

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

  • [@]$1= (6 символов) - медиана трех значений в стеке

Вот еще один потенциально полезный трюк для нахождения мин / макс двух значений , оставляя исходные значения в стеке :

  • .2$>$ (5 символов) - найти минимум два значения в стеке, оставив исходные значения без изменений
  • .2$<$ (5 символов) - найти максимум два значения в стеке, оставив исходные значения без изменений

Это работает так, что .2$клонирует два верхних элемента в стеке в обратном порядке (т.е. a ba b b a), </ >сравнивает копии и возвращает 0 или 1 и скаляр$ затем копирует любое из двух входных значений в зависимости от результата сравнения.


Если у вас в стеке есть два неотрицательных целых числа, вы можете использовать ,\,&,(5 символов), чтобы найти их минимум и,\,|, (5 символов), чтобы найти их максимум. Этот трюк использует набор пересечения и объединения, соответственно, в диапазонах. Вы можете сохранить другого персонажа, если возможно применить, к каждому аргументу отдельно без необходимости их обмена. Поскольку этот метод вычисляет диапазон для каждого аргумента, он не очень эффективен для больших чисел, но может быть очень полезен для меньших входных данных.

Еще более короткий способ найти минимум двух неотрицательных целых чисел в стеке ,<,(3 символа). Увы, этот трюк не работает для нахождения максимума.


абсолютная величина

GolfScript встроенной в абсолютной величине оператора являетсяabs (3 символами). Хотя это на два знака больше, чем я бы предпочел, в целом сложно победить.

В некоторых случаях (например, для сортировки по абсолютному значению) вы можете найти квадрат числа адекватной заменой его абсолютного значения; это может быть вычислено в двух символах, либо 2?или.* . Таким образом, мы получаем:

  • {.*}$0= (7 символов) - минимальный элемент по абсолютному значению в массиве
  • {.*}$-1= (8 символов) - максимальный элемент по абсолютному значению в массиве

Аналогично, вместо проверки, например, если абсолютное значение числа меньше 3 с abs 3<(6 символов, включая пробел), вы можете проверить, если его квадрат меньше 9 с .*9<(4 символа, пространство не требуется).

Илмари Каронен
источник
Если у вас в стеке есть два неотрицательных целых числа, вы можете использовать ,\,&,(5 символов), чтобы найти их минимум, и ,\,|,(5 символов), чтобы найти их максимум. Этот трюк использует набор пересечения и объединения, соответственно, в диапазонах. Вы можете сохранить другой символ, если есть возможность применить ,к каждому аргументу отдельно без необходимости их обмена. Поскольку этот метод вычисляет диапазон для каждого аргумента, он не очень эффективен для больших чисел, но может быть очень полезен для меньших входных данных.
KirarinSnow
@KirarinSnow: Спасибо! Я добавил это к ответу.
Илмари Каронен
4

Удаление дубликатов из массива

Операторы набора |(объединение), &(пересечение) и ^(симметричная разность) объединят несколько элементов массива в один. Таким образом, самый простой способ удалить дублирующиеся элементы из массива - это взять его объединение или пересечение с самим собой:

.|

или:

.&

Эти операторы будут обрабатывать строки как массивы символов, поэтому их также можно использовать для удаления повторяющихся символов из строк.

Илмари Каронен
источник
4

Ограниченная транслитерация

Для решения конкретного подвопроса: учитывая строку, каков наилучший способ выполнить tr ? Напримерtr/ABC/abc/

Если затронуты все символы в строке, это довольно просто: {'ABC'?'abc'=}% (накладные расходы: 9 символов).

Тем не менее, это ломается, если некоторые символы не транслитерируются и 'ABC'?дает-1 .

Если транслитерация нециклическая, ее можно выполнять по одной замене за раз с разбивкой строк и объединениями: 'AaBbCc'1/2/{~@@/\*}/(накладные расходы: 15 символов). Это может быть неправдоподобно, но есть альтернативный подход, который в настоящее время лучше и работает для циклической транслитерации.

В настоящее время кратчайшие общие решения имеют накладные расходы из 14 символов:

  • Один из подходов включает escape-символ:, где обозначает буквальный нулевой байт. (Конечно, этот метод не является полностью общим: он не может отобразить любой другой символ в нулевой байт.){.'ABC'?'abc0'=\or}%0

  • Альтернативно, {.'ABC'?'abc'@),+=}%имеет те же издержки, но использует только печатные символы ASCII. Это @),+сложный (но, по-видимому, самый короткий) способ гарантировать, что строка замены всегда заканчивается вводимым символом.

Питер Тейлор
источник
Используя последний подход, для входной строки 'ABCDEF'я получаю результат 'abc000', но правильный результат будет 'abcDEF'. Я что-то пропустил?
Кристиан Лупаску
1
@ w0lf, это 0 выделено жирным шрифтом, потому что это ранее упомянутый escape-символ - то есть байт 0.
Питер Тейлор,
4

Превратить строку в массив символов

Вы можете сделать это, набрав: 1/после него.

Пример: "String"1/подталкивает к стеку массива ['S''t''r''i''n''g'].

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

user3700847
источник
1
Можете ли вы привести пример того, как это может быть удобно? Строки уже действуют как массивы, так что это не кажется полезным.
Джастин
@Quincunx это удобно, когда вы хотите выдавать символы, а не их значение ascii
user3700847
И когда вы захотите это сделать?
Джастин
5
@Quincunx: вращение строки, например. "abc"1/(+-> "bca", но "abc"(+-> bc97.
Деннис
4

Присвоение числовым литералам

Часто вместо того, чтобы писать 1:xи затем использовать / обновлять переменную x, вы можете просто использовать и обновлять 1напрямую:

1:^;{^.p.+:^;}5*
{1.p.+:1;}5*       (4 bytes shorter)

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

Пунктуация как имена переменных

Если есть к переменным использования, это также часто целесообразно использовать знаки препинания , которые не уже в вашем коде - много программ может обойтись без &,| , ^или ?. Таким образом, например, вы можете написать &nвместо x nнажатия на переменную, а затем нажать на новую строку.

Линн
источник
3
Некоторые задания могут иметь неожиданные побочные эффекты. В частности, приписывая !часто плохая идея, так как она будет ломаться ifи do(так же как while, until, and, orи xor). Аналогичным образом , orопределяется интерпретатором в качестве псевдонима 1$\if, поэтому переопределения 1, $или \будет также разорвать его. Пересмотр `перерывов p.
Илмари Каронен
3

Фильтрация массива

Наиболее общий способ фильтрации массива - это использование { },, которое оценивает блок кода для каждого элемента массива и выбирает те элементы, для которых полученное значение является истинным (то есть оно действует как grepв Perl).

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

  • a b -: удалить все элементы, найденные в массиве bиз массиваa
  • a. b --: удалить все элементы, не найденные в массиве bиз массиваa

В частности, это можно использовать для подсчета количества раз, когда элемент встречается в массиве:

  • a.[c]--,: подсчитать, сколько раз элемент cвстречается в массивеa

В общем, этот метод не является оптимальным, так как любой из:

  • a[c]/,(: подсчитать, сколько раз элемент cвстречается в массивеa
  • a{c=},,: подсчитать, сколько раз элемент cвстречается в массивеa

на один символ короче (и, если счетчик выключен на один, можно a[c]/,сохранить еще один символ). Тем не менее, в особом случае, где cчисло и aнормальный массив (не строка), квадратные скобки вокруг cмогут быть опущены, потому что- оператор приводит свои аргументы к тому же типу:

  • a.c--,: подсчитать, сколько раз число cвстречается в массиве (не строка!)a

(Если aэто строка и cчисло от 0 до 9,a.c-- будет подсчитываться, сколько раз встречается цифра c вa .)


Подобный трюк может быть использован для поиска наиболее распространенного элемента в массиве :

:a{a\[.]-,}$0=

Опять же, если ввод представляет собой массив чисел, вся [.]последовательность может быть опущена. Увы, это не работает для строк без[.] .

Илмари Каронен
источник
Для подсчета вхождений (общий случай) a[c]/,(и a{c=},,на один байт короче.
Деннис
@ Денис: Спасибо! Я редактировал это в.
Ильмари Каронен
3

Читать из STDIN

GolfScript может читать со стандартного ввода:

"#{STDIN.read}"

Это продолжит чтение из STDIN, пока не будет достигнут EOF. В качестве альтернативы:

"#{STDIN.gets}"

или

"#{STDIN.readline}"

Другие доступные вещи:

getbyte
getc
gets([sep])
gets(limit)
gets(sep, limit)
inspect # perhaps useful for an underhanded contest
isatty
read([length])
readbyte
readchar
readline([sep])
readline(limit)
readline(sep, limit)
readlines([sep])
readlines(limit)
readlines(sep, limit)
readpartial(maxlen [, outbuf])

Для каждого из них они могут использоваться только один раз (а также один раз для каждого изменения параметра, также еще раз с пустыми скобками); после этого исходное значение - это то, что вы получите вместо нового значения.

Джастин
источник
2
Возможно, вы захотите добавить замечание, которое {"#{STDIN.readline}"p}2*не читает 2 строки, но вместо этого строка оценивается только один раз.
Говард
2
Если вы инициализируете iлюбое целое число, '"#{'i):i';STDIN.gets}"'++~каждый раз будет оцениваться другой результат. Также стоит упомянуть о кавычках. Если мы предполагаем Linux, мы можем использовать, например, `head -1`вместо STDIN.gets.
Деннис
@Dennis: "#{var'g','gpush Gstring.new(STDIN.gets)'.cc}";также позволит вам определить новый оператор GolfScript, g который читает строку из stdin и помещает ее в стек.
Ильмари
2

Расшифровка шестнадцатеричного ввода

GolfScript не имеет шестнадцатеричных целочисленных литералов, поэтому, увы, вы не можете просто проанализировать шестнадцатеричный ввод ~. Вместо этого, если ваш код должен принимать шестнадцатеричный ввод, вам придется анализировать его вручную.

Этот цикл из 8 символов, примененный к строке, преобразует строчные шестнадцатеричные цифры в их числовые эквиваленты:

{39%9-}%

Если вам необходимо (также) принимать заглавные шестнадцатеричные цифры, самое простое (и, вероятно, самое короткое) решение состоит в том, чтобы сначала сделать их строчными 32|, всего 11 символов:

{32|39%9-}%

Обратите внимание, что технически выходные данные по-прежнему будут строкой (состоящей из символов ASCII 0–15), но большинство функций массива GolfScript также будут принимать строки. Если вам абсолютно необходим массив, вы всегда можете использовать его [{39%9-}/](где первый [необязателен, если в противном случае стек пуст).

Чтобы преобразовать вывод кода выше в целое число, вы можете просто использовать 16base(6 символов). Если вам нужен массив байтов, самое короткое решение, которое я нашел, - просто декодировать каждую пару шестнадцатеричных цифр с помощью 2/{16base}%(11 символов). Все вместе, самый короткий код, который я нашел, чтобы превратить шестнадцатеричную строку в байтовый массив, составляет 8 + 11 = 19 символов:

{39%9-}%2/{16base}%

Обратите внимание , что выход из этого кода является действительно массивом, а не строка. При необходимости, вы можете stringify его конкатенации его , например , с ""+или, если вы не возражаете дополнительный символ новой строки в конце n+.

Илмари Каронен
источник
2

Определение новых встроенных операторов

Стандартный интерпретатор GolfScript имеет редко используемую функцию которая позволяет интерполировать код Ruby в строковых литералах в двойных кавычках.

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

Однако одна вещь, для которой эта функция полезна, - это определение новых операторов GolfScript, реализованных в коде Ruby. Например, вот как определить новый оператор двоичного сложения, который работает так же, как стандартный встроенный +оператор:

"#{var'add','gpush a+b'.cc2}";

Неважно, где вы поместите определение в своем коде; новый оператор определяется, как только разбирается строка в двойных кавычках, содержащая код Ruby. addОператор , определенный выше работ точно , как встроенный +оператор, и может быть использован точно таким же образом:

1 2 add          # evaluates to 3
"foo" "bar" add  # evaluates to "foobar"

Конечно, определение нового оператора сложения довольно бесполезно, если только вы не сделали что-то глупое, например, стерли встроенный+ оператор . Но вы можете использовать тот же прием для определения новых операторов, которые делают вещи, которые Golfscript не может (легко) сделать изначально, например, например, равномерно перемешивая массив:

"#{var'shuf','gpush a.factory(a.val.shuffle)'.cc1}";

10,shuf          # evaluates to 0,1,2,...,9 in random order

или распечатать содержимое всего стека:

"#{var'debug','puts Garray.new($stack).ginspect'.cc}";

4,) ["foo" debug  # prints ["" [0 1 2] 3 "foo"], leaving the stack untouched

или интерактивный ввод:

"#{var'gets','gpush Gstring.new(STDIN.gets)'.cc}";

]; { "> " print gets ~ ]p 1 } do   # simple GolfScript REPL

или даже веб-доступ:

"#{
  require 'net/http'
  require 'uri'
  var'get','gpush Gstring.new(Net::HTTP.get_response(URI.parse(a.to_s)).body)'.cc1
}";

"http://example.com" get

Конечно, несколько более подходящая (и более рискованная!) Реализация последней будет, например:

"#{var'get','gpush Gstring.new(`curl -s #{a}`)'.cc1}";

Несмотря на то, что сам по себе гольф не является особенным, это позволяет расширить возможности GolfScript за пределы возможностей встроенных команд.


Как это работает?

Авторитетная справка о том, как определить новые операторы GolfScript таким образом, является, конечно, исходным кодом для интерпретатора . Тем не менее, вот несколько быстрых советов:

  • Чтобы определить новый оператор, nameкоторый запускает код Ruby code, используйте:

    var'name','code'.cc
  • Внутри кода используйте, gpopчтобы прочитать значение из стека и gpushвставить его обратно. Вы также можете получить доступ к стеку напрямую через массив $stack. Например, чтобы подтолкнуть обе aи bна стек, это golfier делать $stack<<a<<bчем gpush a;gpush b.

    • Позиции [маркеров начала массива сохраняются в $lbмассиве. gpopФункция заботится о настройке этих маркеров вниз , если стек психиатры ниже своего положения, но манипулируя $stackмассив непосредственно не делает.
  • .ccСтроковый метод , который компилирует код на Ruby в строке в оператор GolfScript просто удобство обертка Gblock.new(). Она также имеет варианты .cc1, .cc2и .cc3что делает оператор автоматически выскочит 1, 2 или 3 -х аргументов из стека и назначить их переменным a, bи c. Есть также .orderметод, который работает аналогично .cc2, за исключением того, что он автоматически сортирует аргументы по приоритету типа .

  • Все значения в стеке GolfScript являются (и должны быть!) Объекты типа Gint, Garray, Gstringили Gblock. Базовое целое число или массив, где это необходимо, могут быть доступны через.val метода.

    • Однако обратите внимание, что Gstring.valвозвращает массив Gints! Чтобы превратить a Gstringв собственную строку Ruby, .to_sвместо этого вызовите ее (или используйте ее в контексте, который делает это автоматически, например, при интерполяции строк). Вызов .to_gsлюбого значения GS превращает его в a Gstring, поэтому любое значение GS может быть зачеркнуто .to_gs.to_s.
  • gpushФункция не автоматически завернуть родные Рубиновые числа, строки или массивы в соответствующие типы GS, так что вы часто должны делать это сами явным вызовом , например ,Gstring.new() . Если вы поместите в стек что-либо, кроме одного из типов значений GS, любой код, который позже попытается манипулировать им, может привести к сбою.

  • Типы значений GS также имеют .factoryметод, который вызывает конструктор типа, который может быть полезен, например, для переупаковки массивов / строк после манипулирования их содержимым. У всех типов также есть .coerceметод, который выполняет приведение типов : a.coerce(b)возвращает пару, содержащую aи приведенную bк одному и тому же типу.

Илмари Каронен
источник