Что, этот пост еще не существует?
Конечно, GolfScript это сделано для игры в гольф, так что вы могли бы подумать , что никаких конкретных советов не действительно необходимы. Но чтобы в полной мере использовать возможности GolfScript, вам необходимо изучить некоторые неочевидные приемы. Этот пост предназначен для сбора полезных советов и подсказок.
Для начала, вот официальные справочные страницы GolfScript. Вы должны действительно ознакомиться с этим в первую очередь:
В частности, я бы очень рекомендовал читать страницы в таком порядке - краткий справочник малопригоден, пока вы уже не достаточно хорошо знакомы со встроенными модулями, а учебник содержит некоторые важные детали, которые не объяснены на других страницах. ,
Ps. Ради вдохновения и личного интереса, вот несколько вопросов, которые я бы бы получить хорошие ответы:
Как сделать ограниченную транслитерацию в GolfScript?
{FROM?TO=}%
работает, если вы можете быть уверены, что все входные данные найденыFROM
(или не против того, чтобы все они отображались на последний элементTO
), но все способы, которые я видел для оставления неизмененных значений без изменений, были более или менее полезны.Как лучше всего преобразовать строку в массив кодов ASCII и обратно? Какие операции делают это как побочный эффект? Каков наилучший способ выбросить символы в строке в стек (как это
~
делается для массивов)?
источник
... x
в... [x]
? Лучшее, что я могу видеть, это[.;]
.x
число, то[]+
работает и на один символ короче. И, конечно же, еслиx
в стеке стоит только одно, то просто]
подойдет.Ответы:
Рациональный / Поплавок / Комплекс
Я столько раз читал, что в GolfScript есть только целые числа, и я начал в это верить. Ну, это не правда.
Выход
со стандартным интерпретатором GolfScript и
на веб-сайте GolfScript .
Подобные хаки позволяют разыгрывать в Rational, Float или даже Complex:
источник
Gint.new(@val**b.val)
. Похоже, что вGint
конструкторе отсутствует int int ...Отрицание числа
В GolfScript не хватает только встроенного оператора отрицания. Очевидные способы преобразования числа в стеке в его отрицательное значение, например
-1*
or или0\-
, требуют трех символов. Тем не менее, есть способ сделать это в два:Это работает, потому что GolfScript использует арифметику дополнения до двух , так что ~ x равно - x −1.
Конечно, вариант
(~
также работает; Выбор между ними - дело вкуса.источник
Перетасовывать массив
Самый простой способ перемешать массив в GolfScript - это отсортировать его по ключу случайной сортировки. Если вам нужно только грубо перемешать несколько значений, подойдет следующий код:
Обратите внимание, что даже для коротких списков это не даст очень хорошей случайности. Из-за парадокса дня рождения , чтобы получить достаточно равномерную перестановку, аргумент
rand
должен быть значительно больше, чем квадрат длины перетасовываемого списка.Замена
9
вышеупомянутого99
таким образом дает достаточно хорошие результаты для списков до десяти элементов, но демонстрирует заметное смещение для более длинных списков.Следующий код, который использует 9 9 = 387 420 489 возможных значений, подходит для примерно 1000 элементов или около того (и приемлем для примерно до 20 000):
Для действительно длинных списков добавьте еще 9 для 99 99 ≈ 3,7 × 10 197 значений:
Тестирование:
Вот распределение первого элемента в 10-элементном списке, перетасованном с использованием различных вариантов, показанных выше, с выборкой из 10 000 испытаний:
Вывод
10,{;9rand}$0=
показывает очень четкое смещение, с0
вероятностью более чем в три раза оказаться в первой позиции, как1
:При этом
10,{;99rand}$0=
большая часть предвзятости исчезла, но заметное количество все еще остается:При
10,{;9.?rand}$0=
этом выходные данные практически не отличаются от действительно случайной выборки:Ps. Для действительно плохой перестановки числовых массивов или строк иногда может быть приемлем следующий код:
Как правило, это будет смехотворно смещено, но до тех пор, пока все элементы входного массива (или все коды символов в строке) больше единицы, он имеет ненулевую вероятность создания любой перестановки массива, которая иногда может удовлетворять плохо написанные требования к вызову.
источник
Чтобы решить конкретный вопрос:
Для тех, кто не понимает проблему, система типов GolfScript отдает приоритет типам в порядке: целое число, массив, строка, блок. Это означает, что обычные операции с массивами, применяемые к строке, почти всегда дают вам строку. Например
покинет
'BCD234'
в стеке.В результате лучший способ преобразовать строку в массив кодов ASCII - это почти наверняка сбросить символы в стек и затем собрать их в массив.
Каков наилучший способ выбросить символы в строке в стек?
{}/
Какой лучший способ преобразовать строку в массив кодов ASCII?
[{}/]
(с обычной оговоркой, что если в стеке больше ничего нет, вы можете пропустить[
)Каков наилучший способ преобразовать массив кодов ASCII в строку?
''+
(Обратите внимание, что это также выравнивает массив, например,[65 [66 67] [[[49] 50] 51]]''+
дает'ABC123'
)источник
[]+''+
? (кажется довольно долго)Если ваша программа таинственно ломается, проверьте ваши переменные
Я просто потратил некоторое время на отладку, по-видимому, правильной программы, которая использовалась
!
в качестве переменной (на том основании, что я не собирался использовать ее снова). К сожалению , я сделал использованиеif
, и оказывается, что осуществлениеif
звонков ,!
чтобы решить , какая ветвь следовать.источник
Заворачивание верхнего элемента стека в массив
Для полной общности лучшим вариантом является 4 символа. Однако в некоторых особых случаях это можно уменьшить.
1 символ
]
работает в особом случае, чтоx
является единственным в стеке.3 символа
[]+
работает в особом случае, которыйx
является целым числом..,/
работает в особом случае, которыйx
является истинным массивом или строкой. Например,"AB".,/
дает["AB"]
;3,.,/
дает[[0 1 2]]
. Впрочем,"".,/
и то и[].,/
другое дают[]
.4 символа
[.;]
работает безоговорочно.источник
Это хороший вопрос. Не существует прямого способа присвоить значение элементу массива в 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'
переменнойx42
, в то время какполучит это.
Вы можете оптимизировать это далее, пропустив
x
префикс и просто присваивая непосредственно числовым литералам - это совершенно законно в GolfScript и позволяет вам сохранить один символ из кода присваивания и сократить код извлечения до всего`~
(или вообще ничего, если индекс постоянен!). Недостатком, конечно, является то, что присвоение числового литерала переопределит значение этого литерала где-либо еще в вашем коде. Однако часто можно избежать использования числовых литералов (или, по крайней мере, ограничить их началом до того, как какой-либо из них будет переназначен), и в этом случае этот трюк вполне подходит.источник
i
на 9 байтов:.[i=]/[x]*
Конечный выход манипуляции
По умолчанию, когда ваша программа завершается, интерпретатор GolfScript выводит все в стеке, а также заключительный символ новой строки, точно так же, как если бы ваша программа заканчивалась:
В документации не упоминается, что интерпретатор буквально вызывает встроенное
puts
для создания этого вывода, и что это встроенное буквально определяется как:Таким образом, вы можете подавить или манипулировать конечный результат путем переопределения
если вы чувствуете себя действительно скручены). Вот некоторые примеры:
puts
,print
и / илиn
(илиПодавить финальный перевод строки:
(Конечно, вы можете оставить
;
если вы не возражаете против лишней пустой строки в стеке.)Подавить окончательный вывод полностью:
Это перезаписывает
puts
все, что происходит на вершине стека. Если это то, что вы не хотите выполнять, вы можете использовать, например,0:puts;
вместо этого. Обратите внимание, что это также подавляетp
(что определяется как{`puts}:p;
), но вы все равно можете использоватьprint
для вывода, если хотите.источник
nothing
вы имеете в виду\n
?];
для подавления окончательного вывода.мин Макс
Чтобы найти наименьшее / наибольшее значение в массиве, просто отсортируйте его и возьмите первый / последний элемент:
$0=
(3 символа) - минимальный элемент в арри$-1=
(4 символа) - максимальный элемент в массивеЕсли вы знаете длину массива, и она составляет 10 элементов или меньше, вы можете найти максимум в трех символах, заменив
-1
его индексом последнего элемента.Если у вас есть значения в стеке, вы можете сначала собрать их в массив. Для этого иногда полезный трюк заключается в том,
[\]
что два верхних элемента стека[@]
собираются в массив, а три верхних. Таким образом, мы получаем:[\]$0=
(6 символов) - минимум два значения в стеке[@]$0=
(6 символов) - минимум три значения в стеке[\]$1=
(6 символов) - максимум два значения в стеке[@]$2=
(6 символов) - максимум три значения в стекеТа же самая уловка может также использоваться, чтобы найти медиану трех значений, которые иногда могут быть полезны:
[@]$1=
(6 символов) - медиана трех значений в стекеВот еще один потенциально полезный трюк для нахождения мин / макс двух значений , оставляя исходные значения в стеке :
.2$>$
(5 символов) - найти минимум два значения в стеке, оставив исходные значения без изменений.2$<$
(5 символов) - найти максимум два значения в стеке, оставив исходные значения без измененийЭто работает так, что
.2$
клонирует два верхних элемента в стеке в обратном порядке (т.е.a b
→a 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 символов), чтобы найти их максимум. Этот трюк использует набор пересечения и объединения, соответственно, в диапазонах. Вы можете сохранить другой символ, если есть возможность применить,
к каждому аргументу отдельно без необходимости их обмена. Поскольку этот метод вычисляет диапазон для каждого аргумента, он не очень эффективен для больших чисел, но может быть очень полезен для меньших входных данных.Удаление дубликатов из массива
Операторы набора
|
(объединение),&
(пересечение) и^
(симметричная разность) объединят несколько элементов массива в один. Таким образом, самый простой способ удалить дублирующиеся элементы из массива - это взять его объединение или пересечение с самим собой:или:
Эти операторы будут обрабатывать строки как массивы символов, поэтому их также можно использовать для удаления повторяющихся символов из строк.
источник
Ограниченная транслитерация
Для решения конкретного подвопроса: учитывая строку, каков наилучший способ выполнить
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/
после него.Пример:
"String"1/
подталкивает к стеку массива['S''t''r''i''n''g']
.Это удобно, когда вы хотите перемещать символы вокруг строки.
источник
"abc"1/(+
->"bca"
, но"abc"(+
->bc97
.Присвоение числовым литералам
Часто вместо того, чтобы писать
1:x
и затем использовать / обновлять переменнуюx
, вы можете просто использовать и обновлять1
напрямую:Конечно, это также работает для других начальных значений, но будет прерываться, если это значение встречается где-либо еще в вашем коде.
Пунктуация как имена переменных
Если есть к переменным использования, это также часто целесообразно использовать знаки препинания , которые не уже в вашем коде - много программ может обойтись без
&
,|
,^
или?
. Таким образом, например, вы можете написать&n
вместоx n
нажатия на переменную, а затем нажать на новую строку.источник
!
часто плохая идея, так как она будет ломатьсяif
иdo
(так же какwhile
,until
,and
,or
иxor
). Аналогичным образом ,or
определяется интерпретатором в качестве псевдонима1$\if
, поэтому переопределения1
,$
или\
будет также разорвать его. Пересмотр`
перерывовp
.Фильтрация массива
Наиболее общий способ фильтрации массива - это использование
{ },
, которое оценивает блок кода для каждого элемента массива и выбирает те элементы, для которых полученное значение является истинным (то есть оно действует как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[c]/,(
иa{c=},,
на один байт короче.Читать из STDIN
GolfScript может читать со стандартного ввода:
Это продолжит чтение из STDIN, пока не будет достигнут EOF. В качестве альтернативы:
или
Другие доступные вещи:
Для каждого из них они могут использоваться только один раз (а также один раз для каждого изменения параметра, также еще раз с пустыми скобками); после этого исходное значение - это то, что вы получите вместо нового значения.
источник
{"#{STDIN.readline}"p}2*
не читает 2 строки, но вместо этого строка оценивается только один раз.i
любое целое число,'"#{'i):i';STDIN.gets}"'++~
каждый раз будет оцениваться другой результат. Также стоит упомянуть о кавычках. Если мы предполагаем Linux, мы можем использовать, например,`head -1`
вместоSTDIN.gets
."#{var'g','gpush Gstring.new(STDIN.gets)'.cc}";
также позволит вам определить новый оператор GolfScript,g
который читает строку из stdin и помещает ее в стек.Расшифровка шестнадцатеричного ввода
GolfScript не имеет шестнадцатеричных целочисленных литералов, поэтому, увы, вы не можете просто проанализировать шестнадцатеричный ввод
~
. Вместо этого, если ваш код должен принимать шестнадцатеричный ввод, вам придется анализировать его вручную.Этот цикл из 8 символов, примененный к строке, преобразует строчные шестнадцатеричные цифры в их числовые эквиваленты:
Если вам необходимо (также) принимать заглавные шестнадцатеричные цифры, самое простое (и, вероятно, самое короткое) решение состоит в том, чтобы сначала сделать их строчными
32|
, всего 11 символов:Обратите внимание, что технически выходные данные по-прежнему будут строкой (состоящей из символов ASCII 0–15), но большинство функций массива GolfScript также будут принимать строки. Если вам абсолютно необходим массив, вы всегда можете использовать его
[{39%9-}/]
(где первый[
необязателен, если в противном случае стек пуст).Чтобы преобразовать вывод кода выше в целое число, вы можете просто использовать
16base
(6 символов). Если вам нужен массив байтов, самое короткое решение, которое я нашел, - просто декодировать каждую пару шестнадцатеричных цифр с помощью2/{16base}%
(11 символов). Все вместе, самый короткий код, который я нашел, чтобы превратить шестнадцатеричную строку в байтовый массив, составляет 8 + 11 = 19 символов:Обратите внимание , что выход из этого кода является действительно массивом, а не строка. При необходимости, вы можете stringify его конкатенации его , например , с
""+
или, если вы не возражаете дополнительный символ новой строки в концеn+
.источник
Определение новых встроенных операторов
Стандартный интерпретатор GolfScript имеет редко используемую функцию которая позволяет интерполировать код Ruby в строковых литералах в двойных кавычках.
Одна из причин, почему эта функция не используется чаще, состоит в том, что, к сожалению, интерполированный код выполняется во время компиляции , а выходные данные кэшируются интерпретатором GolfScript, так что один и тот же строковый литерал после этого всегда будет давать одно и то же значение, даже внутри Строка Eval.
Однако одна вещь, для которой эта функция полезна, - это определение новых операторов GolfScript, реализованных в коде Ruby. Например, вот как определить новый оператор двоичного сложения, который работает так же, как стандартный встроенный
+
оператор:Неважно, где вы поместите определение в своем коде; новый оператор определяется, как только разбирается строка в двойных кавычках, содержащая код Ruby.
add
Оператор , определенный выше работ точно , как встроенный+
оператор, и может быть использован точно таким же образом:Конечно, определение нового оператора сложения довольно бесполезно, если только вы не сделали что-то глупое, например, стерли встроенный
+
оператор . Но вы можете использовать тот же прием для определения новых операторов, которые делают вещи, которые Golfscript не может (легко) сделать изначально, например, например, равномерно перемешивая массив:или распечатать содержимое всего стека:
или интерактивный ввод:
или даже веб-доступ:
Конечно, несколько более подходящая (и более рискованная!) Реализация последней будет, например:
Несмотря на то, что сам по себе гольф не является особенным, это позволяет расширить возможности GolfScript за пределы возможностей встроенных команд.
Как это работает?
Авторитетная справка о том, как определить новые операторы GolfScript таким образом, является, конечно, исходным кодом для интерпретатора . Тем не менее, вот несколько быстрых советов:
Чтобы определить новый оператор,
name
который запускает код Rubycode
, используйте:Внутри кода используйте,
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
возвращает массивGint
s! Чтобы превратить aGstring
в собственную строку Ruby,.to_s
вместо этого вызовите ее (или используйте ее в контексте, который делает это автоматически, например, при интерполяции строк). Вызов.to_gs
любого значения GS превращает его в aGstring
, поэтому любое значение GS может быть зачеркнуто.to_gs.to_s
.gpush
Функция не автоматически завернуть родные Рубиновые числа, строки или массивы в соответствующие типы GS, так что вы часто должны делать это сами явным вызовом , например ,Gstring.new()
. Если вы поместите в стек что-либо, кроме одного из типов значений GS, любой код, который позже попытается манипулировать им, может привести к сбою.Типы значений GS также имеют
.factory
метод, который вызывает конструктор типа, который может быть полезен, например, для переупаковки массивов / строк после манипулирования их содержимым. У всех типов также есть.coerce
метод, который выполняет приведение типов :a.coerce(b)
возвращает пару, содержащуюa
и приведеннуюb
к одному и тому же типу.источник