Consejos para jugar golf en GolfScript

35

¿Qué, esta publicación aún no existe?

Por supuesto, GolfScript se hizo para jugar al golf, por lo que se podría pensar que no hay consejos específicos son realmente necesarios. Sin embargo, para hacer un uso completo de las características de GolfScript, usted necesita aprender algunos trucos no evidentes. Este mensaje es para la recogida de este tipo de consejos y trucos útiles.

Para empezar, aquí están las páginas oficiales de referencia GolfScript. Usted realmente debe familiarizarse con estos primeros:

En particular, me gustaría mucho sugerir la lectura de las páginas en este orden - la referencia rápida es de poca utilidad hasta que ya está bastante familiarizado con los muebles empotrados, y el tutorial incluye algunos detalles importantes que no se explican en las otras páginas .


PD. En aras de la inspiración y el interés personal, aquí hay algunas preguntas a las que me gustaría ver buenas respuestas:

  • ¿Cómo hacer transliteración limitada en GolfScript? {FROM?TO=}%funciona si puede estar seguro de que todas las entradas se encuentran FROM(o no les importa que todas estén asignadas al último elemento de TO), pero todas las formas que he visto para dejar los valores no asignados sin cambios han sido más o menos klugey.

  • ¿Cómo convertir mejor una cadena en una matriz de códigos ASCII y viceversa? ¿Qué operaciones hacen esto como efecto secundario? ¿Cuál es la mejor manera de deshacerse de los caracteres de una cadena en la pila (como ~lo hace para las matrices)?

Ilmari Karonen
fuente
Otra pregunta: ¿hay una buena manera de transformar ... xen ... [x]? Lo mejor que puedo ver es [.;].
Peter Taylor
@ Peter: Si xes un número, entonces []+funciona y es un carácter más corto. Y, por supuesto, si xes lo único en la pila, entonces ]lo hará.
Ilmari Karonen
Me gustaría preguntar las mejores formas de hacerlo: mínimo, máximo y valor absoluto. Todas mis soluciones parecen tomar muchos más personajes de los que deberían.
Claudiu
¿Cuál es la mejor manera de modificar una matriz en un índice dado?
user1502040
@ user1502040: respondido a continuación. (Si alguien conoce una mejor manera, ¡por favor comparte!)
Ilmari Karonen

Respuestas:

29

Racional / Flotador / Complejo

He leído tantas veces que GolfScript solo tiene enteros que comencé a creerlo. Pues no es verdad.

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

La salida es

3/4

con el intérprete estándar de GolfScript y

0.75

en Web GolfScript .

Hacks similares permiten lanzar a Rational, Float o incluso Complex:

{-2.?./*}:rational
{2.-1??./*}:float
{-2.-1??./*}:complex
Dennis
fuente
99
OMGWTFHAX o_O !!!
Ilmari Karonen
3
WAT! Estoy bastante seguro de que esto es un error en el intérprete, pero wow
Doorknob
3
Línea 82 del intérprete más reciente: Gint.new(@val**b.val). Parece que al Gintconstructor le falta un elenco int ...
primo
10

Negando un número

Una cosa que le falta a GolfScript es un operador de negación incorporado. Las formas obvias de convertir un número en la pila a negativo, como -1*o 0\-, necesitan tres caracteres. Sin embargo, hay una manera de hacerlo en dos:

~)

Esto funciona porque GolfScript utiliza la aritmética del complemento a dos , de modo que ~ x es igual a - x −1.

Por supuesto, la variante (~también funciona; elegir entre ellos es generalmente una cuestión de gustos.

Ilmari Karonen
fuente
9

Barajar una matriz

La forma más fácil de barajar una matriz en GolfScript es ordenarla por una clave de ordenación aleatoria. Si solo necesita mezclar crudamente algunos valores, el siguiente código funcionará:

{;9rand}$

Tenga en cuenta que, incluso para listas cortas, esto no dará una barajadura muy buena. Debido a la paradoja del cumpleaños , para obtener una mezcla razonablemente uniforme, el argumento pararand debe ser significativamente mayor que el cuadrado de la longitud de la lista que se baraja.

Reemplazando lo 9anterior con99 tanto da resultados razonablemente buenos para listas de hasta diez elementos, pero exhibe un sesgo notable para listas más largas.

El siguiente código, que usa 9 9 = 387,420,489 valores posibles, es válido para hasta aproximadamente 1000 artículos más o menos (y aceptable para hasta aproximadamente 20,000):

{;9.?rand}$

Para listas realmente largas, agregue un 9 más para 99 99 ≈ 3.7 × 10 197 valores:

{;99.?rand}$

Pruebas:

Aquí está la distribución del primer elemento en una lista de 10 elementos barajada usando las diferentes variantes mostradas anteriormente, muestreadas en más de 10,000 ensayos:

  • La salida de 10,{;9rand}$0=muestra un sesgo muy claro, con 0más de tres veces más probabilidades de terminar en la primera posición que 1:

    0 16537 #######################################################
    1 5444  ##################
    2 7510  #########################
    3 8840  #############################
    4 9124  ##############################
    5 12875 ##########################################
    6 9534  ###############################
    7 8203  ###########################
    8 7300  ########################
    9 14633 ################################################
    
  • Con 10,{;99rand}$0=, la mayor parte del sesgo se ha ido, pero aún queda una cantidad notable:

    0 10441 ##################################
    1 9670  ################################
    2 9773  ################################
    3 9873  ################################
    4 10134 #################################
    5 10352 ##################################
    6 10076 #################################
    7 9757  ################################
    8 9653  ################################
    9 10271 ##################################
    
  • Con 10,{;9.?rand}$0=, la salida es básicamente indistinguible de una muestra verdaderamente aleatoria:

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

PD. Para una combinación realmente mala de matrices o cadenas numéricas, el siguiente código a veces puede ser aceptable:

{rand}$

Generalmente será ridículamente sesgado, pero siempre y cuando todos los elementos de la matriz de entrada (o todos los códigos de caracteres en la cadena) sean mayores que uno, tiene una probabilidad distinta de cero de producir cualquier permutación de la matriz, lo que a veces puede satisfacer requisitos de desafío mal escritos.

Ilmari Karonen
fuente
3
Recuerdo que una vez hice escépticamente los cálculos para la paradoja del cumpleaños después de que mi hermano me lo contó, tenía razón :(
ajax333221
8

Para abordar una pregunta secundaria específica:

¿Cómo convertir mejor una cadena en una matriz de códigos ASCII y viceversa? ¿Qué operaciones hacen esto como un efecto secundario? ¿Cuál es la mejor manera de volcar los caracteres en una cadena en la pila (como ~ hace para las matrices)?

Para aquellos que no entienden el problema, el sistema de tipos de GolfScript da prioridad a los tipos en el orden entero, matriz, cadena, bloque. Esto significa que las operaciones de matriz ordinarias aplicadas a una cadena casi siempre le dan una cadena. P.ej

'ABC123'{)}%

dejará 'BCD234'en la pila.

Como resultado, la mejor manera de convertir una cadena en una matriz de códigos ASCII es casi con certeza volcar los caracteres en la pila y luego reunirlos en una matriz.

¿Cuál es la mejor manera de volcar los caracteres en una cadena en la pila? {}/

¿Cuál es la mejor manera de convertir una cadena en una matriz de códigos ASCII? [{}/](con la advertencia habitual de que si no hay nada más en la pila, puede omitir [)

¿Cuál es la mejor manera de convertir una matriz de códigos ASCII en una cadena? ''+(Tenga en cuenta que esto también aplana la matriz, por ejemplo, [65 [66 67] [[[49] 50] 51]]''+da 'ABC123')

Peter Taylor
fuente
¿Cuál es la mejor manera de convertir un único código ASCII en una cadena? []+''+? (parece bastante largo)
Justin
@Quincunx, es bastante largo, pero no conozco una mejor manera. Lo mejor que puede hacer es mirar de dónde vino el código ASCII y ver si puede llegar a una matriz.
Peter Taylor
6

Si su programa se rompe misteriosamente, verifique sus variables

Acabo de pasar un tiempo depurando un programa aparentemente correcto que se usaba !como variable (porque no iba a volver a usarlo). Por desgracia yo hice uso if, y resulta que la aplicación de iflas llamadas !a decidir qué rama a seguir.

Peter Taylor
fuente
6

Envolviendo el elemento superior de la pila en una matriz

¿Hay una buena manera de transformar ... xen ... [x]?

Para una generalidad completa, la mejor opción parece ser 4 caracteres. Sin embargo, en ciertos casos especiales es posible reducir esto.

1 char

]funciona en el caso especial que xes lo único en la pila.

3 caracteres

[]+funciona en el caso especial que xes un entero.

.,/funciona en el caso especial de que xes una matriz o cadena verdadera. Por ejemplo, "AB".,/da ["AB"]; 3,.,/da [[0 1 2]]. Sin embargo, "".,/y [].,/ambos dan [].

4 caracteres

[.;] trabaja incondicionalmente

Peter Taylor
fuente
6

¿Cuál es la mejor manera de modificar una matriz en un índice dado? - user1502040

Buena pregunta. No hay forma directa de asignar un valor a un elemento de matriz en GolfScript, por lo que, de una forma u otra, tendrá que reconstruir toda la matriz.

La forma general más corta que sé para insertar un nuevo valor xen el índice ien una matriz es dividir la matriz en el índice dado y agregarla xa la primera mitad antes de unirlos nuevamente:

  • .i<[x]+\i>+(11 caracteres): inserte el valor xen la matriz en el índice (basado en 0)i

Para reemplazar el valor en el índice icon x, solo necesitamos acortar la segunda mitad de la matriz en un elemento:

  • .i<[x]+\i)>+(12 caracteres): reemplace el elemento en el índice (basado en 0) icon el valorx

Alternativamente, acortar la primera mitad efectivamente hará lo mismo, pero con una indexación basada en 1, que a veces puede ser preferible:

  • .i(<[x]+\i>+(12 caracteres): reemplace el elemento en el índice (basado en 1) icon el valorx

En todos los ejemplos anteriores, si se xtrata de un número, los corchetes que lo rodean pueden omitirse para guardar dos caracteres, ya que de +todos modos se autocontrolará en una matriz :

  • .i<x+\i>+(9 caracteres): inserte el número xen la matriz en el índice (basado en 0)i
  • .i<x+\i)>+(10 caracteres): reemplace el elemento en el índice (basado en 0) icon el númerox
  • .i(<x+\i>+(10 caracteres): reemplace el elemento en el índice (basado en 1) icon el númerox

Los corchetes también se pueden omitir si cualquiera de xlos dos o la "matriz" de entrada (o ambas) son en realidad cadenas, en cuyo caso el resultado también se convertirá en una cadena (usando las reglas habituales de conversión de matriz → cadena).


PD. Como caso especial, si sabemos que la matriz tiene entre i2 y 2 ielementos, podemos insertar un nuevo elemento xen el índice ( basado en 0) icon i/[x]*(6 caracteres). Lo que esto realmente hace es dividir la matriz en fragmentos de hasta ielementos e insertarlos xentre cada fragmento. Tenga en cuenta que, en este caso, los corchetes son necesarios incluso si xes un número.


Pps Un enfoque alternativo es utilizar variables con nombres dinámicos. Por ejemplo,

 'foo' 42 ':x'\+~

asignará el valor 'foo'a la variable x42, mientras

 42 'x'\+~

Lo recuperará.

Puede optimizar esto aún más omitiendo el xprefijo y simplemente asignando directamente a los literales numéricos; esto es perfectamente legal en GolfScript y le permite guardar un carácter del código de asignación y acortar el código de recuperación a solo `~(o nada en absoluto, si ¡El índice es constante!). La desventaja, por supuesto, es que asignar un literal numérico anulará el valor de ese literal en cualquier otro lugar de su código. Sin embargo, a menudo, se puede evitar el uso de literales numéricos (o al menos restringidos al comienzo del programa, antes de reasignarlos), en cuyo caso este truco está perfectamente bien.

Ilmari Karonen
fuente
3
Completamente fuera de tema: ¡felicidades por 10k! :-D
Pomo de la puerta
1
Si sabe que la matriz no tiene valores duplicados, puede reemplazar un valor en el índice ide 9 bytes:.[i=]/[x]*
Martin Ender
5

Manipulación de salida final

Por defecto, cuando finaliza su programa, el intérprete de GolfScript muestra todo en la pila, más una nueva línea final, exactamente como si su programa terminara con:

]puts

Lo que la documentación no menciona directamente es que el intérprete literalmente llama al incorporado putspara producir esta salida, y que este incorporado se define literalmente como:

{print n print}:puts;

Por lo tanto, puede suprimir o manipular la salida final redefiniendo puts, print y / o n(o  si se siente realmente en espiral). Aquí hay unos ejemplos:

Suprimir la nueva línea final:

'':n;

(Por supuesto, puedes dejar de lado el ; si no le importa una cadena vacía adicional en la pila).

Suprimir la salida final por completo:

:puts

Esto se sobrescribe putscon lo que sea que esté encima de la pila. Si resulta que es algo que no desea ejecutar, puede usar, por ejemplo, en su 0:puts;lugar. Tenga en cuenta que esto también suprime p(que se define como {`puts}:p;), pero aún puede usarlo printpara la salida si lo desea.

Ilmari Karonen
fuente
¿Y a nothingqué te refieres \n?
CalculatorFeline
Si no le importa la nueva línea final, también puede usar ];para suprimir la salida final.
wastl
5

Me gustaría preguntar las mejores formas de hacerlo: mínimo, máximo y valor absoluto. Todas mis soluciones parecen tomar muchos más personajes de los que deberían. - Claudiu

mínimo máximo

Para encontrar el valor más pequeño / más grande en una matriz, simplemente ordénelo y tome el primer / último elemento:

  • $0= (3 caracteres) - elemento mínimo en un arry
  • $-1= (4 caracteres): elemento máximo en una matriz

Si conoce la longitud de la matriz y son 10 elementos o menos, puede encontrar el máximo en tres caracteres reemplazando -1con el índice del último elemento.

Si tiene los valores en la pila, puede recopilarlos primero en una matriz. Para esto, un truco ocasionalmente útil es que [\]reúne los dos elementos superiores de la pila en una matriz, mientras [@]recopila los tres primeros. Por lo tanto, obtenemos:

  • [\]$0= (6 caracteres): mínimo de dos valores en la pila
  • [@]$0= (6 caracteres) - mínimo de tres valores en la pila
  • [\]$1= (6 caracteres) - máximo de dos valores en la pila
  • [@]$2= (6 caracteres): máximo de tres valores en la pila

El mismo truco también se puede utilizar para encontrar la mediana de tres valores, que en ocasiones pueden ser útiles:

  • [@]$1= (6 caracteres) - mediana de tres valores en la pila

Aquí hay otro truco potencialmente útil para encontrar el mínimo / máximo de dos valores mientras se dejan los valores originales en la pila :

  • .2$>$ (5 caracteres): encuentre un mínimo de dos valores en la pila, sin modificar los valores originales
  • .2$<$ (5 caracteres): encuentre el máximo de dos valores en la pila, mientras deja intactos los valores originales

La forma en que funciona es que .2$clona los dos elementos superiores en la pila en orden inverso (es decir, a ba b b a), </ >compara las copias y devuelve 0 o 1, y el escalar $luego copia cualquiera de los dos valores de entrada dependiendo del resultado de la comparación.


Si tiene dos enteros no negativos en la pila, puede usar ,\,&,(5 caracteres) para encontrar su mínimo y ,\,|,(5 caracteres) para encontrar su máximo. Este truco usa la intersección y la unión establecidas, respectivamente, sobre los rangos. Puede guardar otro carácter si es posible aplicarlo ,a cada argumento por separado sin tener que intercambiarlos. Dado que este método calcula un rango para cada argumento, no es muy eficiente para números más grandes, pero podría ser muy útil para entradas más pequeñas.

Una forma aún más corta de encontrar el mínimo de dos enteros no negativos en la pila es ,<,(3 caracteres). Por desgracia, este truco no funciona para encontrar el máximo.


valor absoluto

El operador de valor absoluto incorporado de GolfScript es abs(3 caracteres). Si bien esto es dos caracteres más de lo que preferiría, es difícil de superar en general.

En algunos casos (por ejemplo, para ordenar por valor absoluto) puede encontrar el cuadrado de un número como un sustituto adecuado de su valor absoluto; Esto se puede calcular en dos caracteres, ya sea 2?o .*. Por lo tanto, obtenemos:

  • {.*}$0= (7 caracteres): elemento mínimo por valor absoluto en la matriz
  • {.*}$-1= (8 caracteres): elemento máximo por valor absoluto en la matriz

Del mismo modo, en lugar de, por ejemplo, probar si el valor absoluto de un número es menor que 3 con abs 3<(6 caracteres, incluido el espacio), puede probar si su cuadrado es menor que 9 con .*9<(4 caracteres, no se necesita espacio).

Ilmari Karonen
fuente
Si tiene dos enteros no negativos en la pila, puede usar ,\,&,(5 caracteres) para encontrar su mínimo y ,\,|,(5 caracteres) para encontrar su máximo. Este truco usa la intersección y la unión establecidas, respectivamente, sobre los rangos. Puede guardar otro carácter si es posible aplicarlo ,a cada argumento por separado sin tener que intercambiarlos. Dado que este método calcula un rango para cada argumento, no es muy eficiente para números más grandes, pero podría ser muy útil para entradas más pequeñas.
KirarinSnow 01 de
@ KirarinSnow: ¡Gracias! Lo he agregado a la respuesta.
Ilmari Karonen 01 de
4

Eliminar duplicados de una matriz

Los operadores de conjunto |(unión), &(intersección) y ^(diferencia simétrica) colapsarán múltiples elementos de la matriz en uno. Por lo tanto, la forma más sencilla de eliminar elementos duplicados de una matriz es tomar su unión o intersección consigo mismo:

.|

o:

.&

Estos operadores tratarán las cadenas como matrices de caracteres, por lo que también se pueden usar para eliminar caracteres duplicados de las cadenas.

Ilmari Karonen
fuente
4

Transliteración limitada

Para abordar una pregunta secundaria específica: dada una cadena, ¿cuál es la mejor manera de realizar una tr? P.ejtr/ABC/abc/

Si todos los caracteres de la cadena se verán afectados, esto es bastante fácil: {'ABC'?'abc'=}%(gastos generales: 9 caracteres).

Sin embargo, eso se rompe si alguno de los personajes no se transcribe y 'ABC'?da -1.

Si la transliteración no es cíclica, se puede hacer un reemplazo a la vez con divisiones y uniones de cuerdas: 'AaBbCc'1/2/{~@@/\*}/(arriba: 15 caracteres). Esto puede mejorarse, pero hay un enfoque alternativo que actualmente es mejor y funciona para las transliteraciones cíclicas.

Actualmente, las soluciones generales más cortas tienen una sobrecarga de 14 caracteres:

  • Un enfoque implica un carácter de escape: donde denota un byte nulo literal. (Por supuesto, este método no es completamente general: no puede asignar ningún otro carácter a un byte nulo).{.'ABC'?'abc0'=\or}%0

  • Alternativamente, {.'ABC'?'abc'@),+=}%tiene la misma sobrecarga, pero solo usa caracteres ASCII imprimibles. El @),+es una forma enrevesada (pero, aparentemente, la más corta) para garantizar que la cadena de reemplazo siempre termine con el carácter de entrada.

Peter Taylor
fuente
Usando el último enfoque, para la cadena de entrada 'ABCDEF'obtengo el resultado 'abc000', pero el resultado correcto sería 'abcDEF'. ¿Me estoy perdiendo de algo?
Cristian Lupascu
1
@ w0lf, ese 0 está en negrita porque es el carácter de escape mencionado anteriormente, es decir, el byte 0.
Peter Taylor
4

Convierte una cadena en una matriz de caracteres

Puede hacer esto escribiendo: 1/después de eso.

Ejemplo: "String"1/empuja para apilar la matriz ['S''t''r''i''n''g'].

Esto es útil cuando desea mover caracteres alrededor de la cadena.

usuario3700847
fuente
1
¿Puedes dar un ejemplo de cómo esto podría ser útil? Las cadenas ya actúan como matrices, por lo que esto no parece tan útil.
Justin
@Quincunx es útil cuando quieres resaltar caracteres y no su valor
ASCII
¿Y cuándo quieres hacer eso?
Justin
55
@Quincunx: Rotación de una cadena, por ejemplo. "abc"1/(+-> "bca", pero "abc"(+-> bc97.
Dennis
4

Asignación a literales numéricos

A menudo, en lugar de escribir 1:xy luego usar / actualizar la variable x, puede usar y actualizar 1directamente:

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

Por supuesto, esto también funciona para otros valores iniciales, pero se romperá si ese valor ocurre en cualquier otro lugar de su código.

Puntuación como nombres de variables

Si usted tiene que utilizar variables, también es a menudo una buena idea usar puntuacion que no está ya en su código - un montón de programas puede prescindir &, |, ^, o ?. De esta manera, por ejemplo, puede escribir en &nlugar de x npresionar su variable y luego presionar una nueva línea.

Lynn
fuente
3
Sin embargo, algunas tareas pueden tener efectos secundarios inesperados. En particular, asignando a !menudo es una mala idea, ya que se romperá ify do(así como while, until, and, ory xor). Del mismo modo, orel intérprete lo define como un alias para 1$\if, por lo tanto 1, redefinir ,$ o \también lo romperá. Redefiniendo los `descansos p.
Ilmari Karonen
3

Filtrar una matriz

La forma más general de filtrar una matriz es usar { }, , que evalúa el bloque de código para cada elemento de la matriz, y selecciona aquellos elementos para los cuales el valor resultante es verdadero (es decir, actúa como grepen Perl).

Sin embargo, el uso del operador de sustracción de matriz -suele ser más corto. Este operador toma dos matrices y elimina todos los elementos que ocurren en la segunda matriz de la primera. Lo hace no alterar el orden de los elementos en la primera matriz o colapso duplicados. Un truco útil es aplicar la operación de resta dos veces para obtener un operador de intersección de matriz no colapsable:

  • a b -: elimina cualquier elemento encontrado en la matriz bde la matriza
  • a. b --: elimina cualquier elemento que no se encuentre en la matriz bde la matriza

En particular, esto se puede usar para contar la cantidad de veces que un elemento ocurre en una matriz:

  • a.[c]--,: cuenta el número de veces que el elemento cocurre en la matriza

En general, este método no es óptimo, ya que cualquiera de:

  • a[c]/,(: cuenta el número de veces que el elemento cocurre en la matriza
  • a{c=},,: cuenta el número de veces que el elemento cocurre en la matriza

es un carácter más corto (y, si está bien que el recuento sea desactivado por uno, a[c]/, guarda un carácter más). Sin embargo, en el caso especial donde ces un número y aes una matriz normal (no una cadena), cse pueden omitir los corchetes porque- operador coacciona sus argumentos al mismo tipo:

  • a.c--,: cuenta el número de veces que el número caparece en la matriz (¡no cadena!)a

(Si aes una cadena y ces un número entre 0 y 9, a.c--contará la cantidad de veces que c aparece dígitoa ).


Se puede usar un truco similar para encontrar el elemento más común en una matriz :

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

Nuevamente, si la entrada es una matriz de números, [.]se puede omitir toda la secuencia. Por desgracia, esto no funciona para cadenas sin el [.].

Ilmari Karonen
fuente
Para contar sucesos (caso general), a[c]/,(y a{c=},,son un byte más cortos.
Dennis
@ Dennis: ¡Gracias! Lo he editado en.
Ilmari Karonen
3

Leer de STDIN

GolfScript puede leer desde stdin:

"#{STDIN.read}"

Esto continuará leyendo desde STDIN hasta que se alcance el EOF. Alternativamente:

"#{STDIN.gets}"

o

"#{STDIN.readline}"

Otras cosas disponibles:

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])

Para cada uno de estos, solo se pueden usar una vez (y también una vez para cada cambio del parámetro, también una vez más con paréntesis vacíos); después de eso, el valor original es lo que obtendrá en lugar de un nuevo valor.

Justin
fuente
2
Es posible que desee agregar un comentario que {"#{STDIN.readline}"p}2*no lea 2 líneas, sino que la cadena se evalúa solo una vez.
Howard
2
Si inicializa ia cualquier número entero, '"#{'i):i';STDIN.gets}"'++~dará un resultado diferente cada vez que se evalúe. También vale la pena mencionar los backticks. Si asumimos Linux, podemos usar, por ejemplo, en `head -1`lugar de STDIN.gets.
Dennis
@Dennis: "#{var'g','gpush Gstring.new(STDIN.gets)'.cc}";también le permitiría definir un nuevo operador de GolfScript g que lea una línea de stdin y la inserte en la pila.
Ilmari Karonen
2

Decodificación de entrada hexadecimal

GolfScript no tiene literales enteros hexadecimales, así que, por desgracia, no puede simplemente analizar la entrada hexadecimal con ~ . En cambio, si su código debe tomar entrada hexadecimal, deberá analizarlo manualmente.

Este bucle de 8 caracteres, aplicado a una cadena, convertirá dígitos hexadecimales en minúsculas a sus equivalentes numéricos:

{39%9-}%

Si tiene que (también) aceptar dígitos hexadecimales en mayúscula, la solución más fácil (y probablemente la más corta) es primero ponerlos en minúscula 32|, para un total de 11 caracteres:

{32|39%9-}%

Tenga en cuenta que la salida técnicamente seguirá siendo una cadena (que consta de los caracteres ASCII 0 - 15), pero la mayoría de las funciones de la matriz GolfScript también aceptarán cadenas. Si absolutamente necesita una matriz, siempre puede usar [{39%9-}/](donde el primero[ es opcional si la pila está vacía).

Para convertir la salida del código anterior en un número entero, simplemente puede usar 16base(6 caracteres). Si desea una matriz de bytes, la solución más corta que he encontrado es simplemente decodificar cada par de dígitos hexadecimales con 2/{16base}%(11 caracteres). En conjunto, el código más corto que he encontrado para convertir una cadena hexadecimal en una matriz de bytes es 8 + 11 = 19 caracteres:

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

Tenga en cuenta que la salida de este código es de hecho una matriz, no una cadena. Si es necesario, puede stringify que mediante la concatenación de que por ejemplo, con ""+o, si no le importa un salto de línea extra al final, n+.

Ilmari Karonen
fuente
2

Definición de nuevos operadores integrados

El intérprete estándar de GolfScript tiene una característica raramente utilizada que permite el código Ruby interpolado en literales de cadena entre comillas dobles.

Una razón por la cual esta característica no se usa con más frecuencia es que, incómodamente, el código interpolado se ejecuta en tiempo de compilación , y el intérprete de GolfScript almacena en caché la salida para que el mismo literal de cadena siempre produzca el mismo valor, incluso dentro cadena eval.

Sin embargo, una cosa para la que resulta útil esta característica es definir nuevos operadores de GolfScript implementados en el código Ruby. Por ejemplo, aquí se explica cómo definir un nuevo operador de suma binaria que funcione igual que el +operador integrado estándar :

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

Realmente no importa dónde pones la definición en tu código; el nuevo operador se define tan pronto como se analiza la cadena entre comillas dobles que contiene el código Ruby. El addoperador definido anteriormente funciona exactamente como el +operador incorporado , y se puede usar exactamente de la misma manera:

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

Por supuesto, definir un nuevo operador de adición es bastante inútil, a menos que haya hecho algo tonto como borrar el +operador incorporado . Pero puede usar el mismo truco para definir nuevos operadores que hacen cosas que Golfscript no puede hacer (fácilmente) de forma nativa, como, por ejemplo, barajar uniformemente una matriz:

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

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

o imprimir el contenido de toda la pila:

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

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

o entrada interactiva:

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

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

o incluso acceso web:

"#{
  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

Por supuesto, una implementación algo más golfista (¡y más riesgosa!) De este último sería, por ejemplo:

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

Si bien no es particularmente golfoso en sí mismo, esto le permite ampliar las capacidades de GolfScript más allá de lo que proporcionan los comandos integrados.


¿Como funciona?

La referencia autorizada sobre cómo definir nuevos operadores de GolfScript de esta manera es, por supuesto, el código fuente para el intérprete . Dicho esto, aquí hay algunos consejos rápidos:

  • Para definir un nuevo operador nameque ejecute el código Ruby code, use:

    var'name','code'.cc
  • Dentro del código, úselo gpoppara leer un valor de la pila y gpushpara volver a introducir uno. También puede acceder a la pila directamente a través de la matriz $stack. Por ejemplo, para empujar tanto ay ben la pila, es Golfier hacer $stack<<a<<bque gpush a;gpush b.

    • Las posiciones de los [marcadores de inicio de la matriz se almacenan en la $lbmatriz. La gpopfunción se encarga de ajustar estos marcadores hacia abajo si la pila se contrae por debajo de su posición, pero la manipulación de la $stackmatriz no lo hace directamente.
  • El .ccmétodo de cadena que compila el código Ruby en una cadena en un operador de GolfScript es solo una envoltura conveniente Gblock.new(). También tiene las variantes .cc1, .cc2y .cc3eso hace que el operador extraiga automáticamente 1, 2 o 3 argumentos de la pila y los asigne a las variables a, by c. También hay un .ordermétodo que funciona como .cc2, excepto que clasifica automáticamente los argumentos por tipo de prioridad .

  • Todos los valores en la pila GolfScript son (y deben ser!) Los objetos de tipo Gint, Garray, Gstringo Gblock. Se puede acceder al entero nativo subyacente o matriz, donde sea necesario, a través del .valmétodo.

    • Sin embargo, tenga en cuenta que Gstring.valdevuelve una matriz de Gints! Para convertir una Gstringcadena de Ruby en nativa, invoque .to_sen su lugar (o úsela en un contexto que lo haga automáticamente, como la interpolación de cadenas). Invocar .to_gscualquier valor GS lo convierte en a Gstring, por lo que cualquier valor GS puede ser encadenado .to_gs.to_s.
  • La gpushfunción no ajusta automáticamente los números, cadenas o matrices nativos de Ruby en los tipos GS correspondientes, por lo que a menudo tendrá que hacerlo usted mismo llamando explícitamente, por ejemplo Gstring.new(). Si inserta algo que no sea uno de los tipos de valor GS en la pila, es probable que se bloquee cualquier código que luego intente manipularlo.

  • Los tipos de valor GS también tienen un .factory método que llama al constructor del tipo, que puede ser útil, por ejemplo, para reenvolver matrices / cadenas después de manipular sus contenidos. Todos los tipos también tienen un .coercemétodo que realiza la coerción de tipos : a.coerce(b)devuelve un par que contiene ay bcoaccionado al mismo tipo.

Ilmari Karonen
fuente