Поради щодо гольфу в GolfScript


35

Що, ця публікація ще не існує?

Звичайно, GolfScript це зроблено для гри в гольф, так що ви могли б подумати , що ніяких конкретних порад не дійсно необхідні. Але щоб повною мірою використати функції GolfScript, вам потрібно навчитися деяким неочевидним хитрощам. Ця публікація призначена для збору таких корисних порад та рекомендацій.

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

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


Пс. Заради натхнення та особистого інтересу ось кілька питань, на які я хотів би побачити приємні відповіді:

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

  • Як найкраще перетворити рядок у масив кодів ASCII і назад? Які операції роблять це як побічний ефект? Який найкращий спосіб скинути символів у рядку на стек (як ~це робиться для масивів)?


Ще одне питання: чи є приємний спосіб перетворитись ... xна ... [x]? Найкраще, що я бачу, - це [.;].
Пітер Тейлор

@Peter: Якщо xчисло, то воно []+працює і на один знак коротше. І звичайно, якщо xєдине, що стоїть у стеці, то просто ]зробить.
Ільмарі Каронен

Я хотів би запитати найкращі способи виконання: min, max та абсолютне значення. Мої рішення, схоже, мають більше символів, ніж повинні.
Клавдіу

Який найкращий спосіб змінити масив за заданим індексом?
user1502040

@ user1502040: Відповідь нижче. (Якщо хтось знає кращий спосіб, будь ласка, поділіться!)
Ільмарі Каронен

Відповіді:


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 o_O !!!
Ільмарі Каронен

3
ВАТ! Досить впевнений, що це помилка в перекладачі, але ого
Doorknob

3
Лінія 82 з самого останнього перекладача: Gint.new(@val**b.val). Здається, у Gintконструктора відсутній інт-каст ...
прим

10

Заперечення числа

Одне, чого не вистачає GolfScript, - це вбудований оператор заперечення. Очевидні способи перетворення числа на стеку в його мінус, як-от -1*або 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  #################################
    

Пс. Для дійсно поганого перетасування числових масивів або рядків іноді може бути прийнятний наступний код:

{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 char

]працює в спеціальному випадку, який xє єдиним на стеку.

3 символи

[]+працює у спеціальному випадку, який xє цілим числом.

.,/працює в окремому випадку, що xє truthy масивом або рядком. Напр. "AB".,/Дає ["AB"]; 3,.,/дає [[0 1 2]]. Однак "".,/і те й [].,/інше дають [].

4 символи

[.;] працює беззастережно.


6

Який найкращий спосіб змінити масив за заданим індексом? - користувач1502040

Це гарне запитання. Немає прямого способу присвоїти значення елементу масиву в GolfScript, тому, так чи інакше, вам доведеться перебудувати весь масив.

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

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

Щоб замінити значення на індекс iна x, нам просто потрібно скоротити другу половину масиву на один елемент:

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

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

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

У всіх наведених вище прикладах, якщо xце число, квадратні дужки навколо нього можуть бути пропущені, щоб зберегти два символи, оскільки він все одно буде автоматично примусований до масиву +:

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

Дужки також можуть бути опущені, якщо будь-який xабо вхідний "масив" (або обидва) насправді є рядками, і в цьому випадку результат також буде примусований до рядка (використовуючи звичайний масив → правила перетворення рядків).


Пс. Як особливий випадок, якщо ми знаємо, що масив має між iта 2 × iелементами, ми можемо вставити новий елемент xу (індекс на основі 0) iз i/[x]*(6 знаків). Це насправді робить це розділити масив на шматки до iелементів та вставити xміж кожним фрагментом. Зауважте, що в цьому випадку дужки необхідні, навіть якщо xце число.


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

 'foo' 42 ':x'\+~

присвоїть значення 'foo'змінній x42, а

 42 'x'\+~

відновить його.

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


3
Цілком поза темою: вітаємо 10k! :-D
Дверна ручка

1
Якщо ви знаєте, що масив не має повторюваних значень, ви можете замінити значення в індексі iна 9 байт:.[i=]/[x]*
Martin Ender

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

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

хв / макс

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

  • $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 символів:

  • Один із підходів передбачає символ втечі:, де позначається буквальний нульовий байт. (Звичайно, цей метод не зовсім загальний: він не може відобразити жодного іншого символу в нульовий байт.){.'ABC'?'abc0'=\or}%0

  • Крім того, {.'ABC'?'abc'@),+=}%має однакові накладні витрати, але використовує лише друковані символи ASCII. Це @),+складний (але, мабуть, найкоротший) спосіб забезпечити, щоб рядок заміни завжди закінчувався символом введення.


Використовуючи останній підхід, для рядка введення 'ABCDEF'я отримую результат 'abc000', але правильний результат був би 'abcDEF'. Я щось пропускаю?
Крістіан Лупаску

1
@ w0lf, що 0 виділяється жирним шрифтом, тому що це попередньо згадуваний символ втечі - тобто байт 0.
Пітер Тейлор

4

Поверніть рядок до масиву char

Це можна зробити, ввівши: 1/після нього.

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

Це зручно, коли потрібно перемістити символи навколо рядка.


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=},,вони на один байт коротші.
Денніс

@Dennis: Дякую! Я це відредагував.
Ілмарі Каронен

3

Читайте з STDIN

GolfScript може читати з stdin:

"#{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на стек, це робити гольфіст, $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Функція не автоматичне обруча рідні номери Ruby, рядки або масиви в типах відповідних GS, так що вам часто доводиться робити це самостійно явним викликом , наприклад Gstring.new(). Якщо ви натиснете на стек що-небудь, крім одного з типів значень GS, будь-який код, який пізніше намагається маніпулювати ним, може зірватися.

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

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