GolfScript se sale con la suya con demasiada frecuencia y creo que un depósito de consejos prácticos para jugar golf en J podría ayudar en la lucha contra el imperio del mal. ¿Qué consejos tienes para acortar este lenguaje ya conciso?
Para aquellos que quieran aprender J, el lugar obvio para comenzar es el sitio jsoftware y particularmente el vocabulario , la guía Learning J y la guía J for C para programadores .
GolfScript gets its own way far too often
en 2019.Respuestas:
Hay una serie de sutilezas para exprimir los últimos caracteres en J. Para lo siguiente, suponga que cada letra mayúscula es un verbo primitivo (es decir, estoy eliminando los espacios que de otro modo serían necesarios para delimitar nombres).
Cuando tienes un tren en marcha, y necesitas aplicar una función encima de otra a mitad de camino,
([:FLGR)
y(LF@:GR)
tener el mismo número de caracteres, pero(LF@GR)
guarda uno. Si el marco de G es mayor o igual que el rango de mónada de F, esta es una transformación válida. Notablemente, todos los trenes tienen un rango infinito, al igual que la, ,. ,: ~. /: \: [ ]
mayoría de los usos de#
y|.
.Si tiene que elegir cadenas de una lista, y estas cadenas no tienen espacios, use
>i{ab`cd`ef
. Está sucio, pero guarda caracteres para cada nueva cadena con la que tiene que lidiar, a menos que solo extraiga caracteres individuales, e incluso entonces la lista de caracteres debe ser de longitud 4 para ser más corta. Lo que sucede es que los nombres indefinidos se tratan como referencias a los verbos, y cuando tomas los gerundios de esos verbos obtienes una cadena encuadrada del nombre. Cualquier nombre que ya esté definido como que tenga tipo de sustantivo, adverbio o conjunción no se puede usar de esta manera, porque esos nombres se resuelven antes y`
pueden tenerlos.Si tiene la suerte de tener una expresión con la que trabajar y no solo un verbo tácito, casi siempre vale la pena asignar los bits que reutiliza a las variables, ya sean sustantivos, verbos o adverbios. Los padres a veces se pagan a sí mismos al ajustarse directamente a donde tenía espacios antes, y la mayoría de esas definiciones valen la pena si se reutilizan una vez más.
Las conjunciones como
(FGH)^:(u`v`w)
se pueden reescribiru`v`w(FGH^:)
. Esto funciona para cualquier longitud de tren, incluso 1, aunque solo guarda algo si este truco elimina a los padres del argumento correcto. Este truco solo funciona cuando precarga el operando izquierdo. (¿No tiene idea de lo que acaba de pasar? Busque 'adverbios tácitos' y estudie la sección Análisis y ejecución del Diccionario J).¡No uses
a.&i.
, usau:
!{&a.
y3&u:
son equivalentes en longitud, sin embargo, y el primero podría ser más útil en una conjunción (dependiendo de la conjunción).Cosas como
(2%~F)
y(F%2:)
son equivalentes en longitud. Esto es útil porque a veces, dependiendo de cómo se vea el resto de tu tren, puedes reestructurarlo con@
trucos como están escritos en el primer punto, para salvar a algunos personajes desesperados. (Y, por supuesto, siF
es así]
y el tren es una mónada, usando%&2
salva un char, duh).Trenes en forma de gancho con
]
o[
como el verbo más a la izquierda, p(]FGH)
.]
le permite romper una aplicación diádica y usar solo el argumento correcto. (Cambia a la izquierda con(]FGH)~
una penalización de al menos 1 personaje, tal vez más). ¡Salva un char(FGH)@]
, y es muy útil en gerundios![
en un gancho aplicado de forma monádica le permite hacer algo por los efectos secundarios en el lado derecho, luego devolver el argumento nuevamente. El uso más común es con1!:2
, posiblemente con formato de basura.I / O es una mierda. Acelere el proceso haciendo bucles de todo lo que pueda.
1!:1
tiene rango0
, y ambos1!:2 3
tienen rango_ 0
, por ejemplo, así que utilícelo haciendo matrices de 1s y corra1!:1
directamente sobre ellos. Tenga en cuenta que".
también tiene rango 1, por lo que generalmente puede colocarlo directamente después1!:1
, y no tener que adjuntarlo a través de@
travesuras de rango.No es fácil encontrar lugares para colocar esto, pero
::
puede ser útil.::]^:_
es una combinación particularmente poderosa, por ejemplo, que te permite hacer algo peligroso hasta que ya no puedas hacerlo. (Sujeto a las^:_
advertencias habituales como un bucle).Esto también le permite usar
{
en listas que no tienen el índice deseado, porque arroja un error de dominio cuando eso sucede. Útil para, por ejemplo, tomar el encabezado de una lista solo si existe (intente usar::]
para devolver la lista vacía, o::_1:
para devolver un código de error, y así sucesivamente).]`($:@u)@.v
generalmente se puede hacer más corto queu^:v^:_
, especialmente en las definiciones deu
y con lasv
que se puede jugar. Un caso similar es válido para el condicional comou^:(1-v)
vs]`[email protected]
. Considere sus opciones, especialmente cuando tiene muchos verbos nombrados flotando. También es un poco más flexible, pero recuerde, si lo usa$:
, hay una profundidad de recursión con la que es fácil toparse. (¿Suele ser algo así como 1800 iteraciones?)fuente
%&2
salva un char, duh". ¡Y-:
salva a otro!Lo más importante al jugar golf en J es no solo entender el problema, sino reducirlo a una serie de transformaciones de matriz. Debe comprender esta forma de pensar para tener éxito con el código J.
Por ejemplo, un desafío reciente pidió resolver el mayor problema de subarreglos . El algoritmo estándar para resolver este problema es el algoritmo de Kadane que tiene la siguiente descripción informal:
Una traducción al código imperativo es sencilla:
Este algoritmo parece complicado para J de un vistazo, ya que hay un ciclo explícito que al principio no parece una reducción. Si se da cuenta de lo que está haciendo el algoritmo, puede desenredar los pasos individuales y ver que realmente realiza dos operaciones de matriz simples:
Ahora estos dos pasos son muy fáciles de implementar en J. Aquí hay una traducción:
(0 >. +)/\. y , 0
- Este paso opera desde el otro extremo de la matriz para adaptarse mejor al paradigma de J.0 >. +
es tácito0 >. x + y
.>./ y
En conjunto, obtenemos una implementación muy concisa del algoritmo:
Si aprende esta forma de abordar la implementación de algoritmos, sus soluciones serán tan claras como este código.
Aquí hay algunos trucos que acumulé con el tiempo. Esta lista se ampliará a medida que obtenga más conocimiento en J golf.
=
es extraño al principio, pero es muy útil en los desafíos de arte ASCII.&
en contextos tácitos cuando desee una conjunción de poder. El vocabulario sugiereu@[&0
como un reemplazo tácito4 : 'u^:x y
y yo también.[:
o@:
en una secuencia comou@v
si eligiera una varianteu
que tenga un argumento izquierdo. Por ejemplo, para descartar el primer elemento del resultado dev
, use en1}.v
lugar de[:}.v
si}.@v
no es posible por alguna razón.] v
a menudo es más corto quev@]
si desea usar monádicov
en un contexto diádico. Esto resulta útil especialmente cuando sev
trata de un largo tren de verbos.m (n v w) y
lugar de(n v m&w) y
. Esto puede hacer posible evitar espacios y paréntesis.#\
en lugar de>:@i.@#
.u &. v
Es útil cuandov
tiene un anverso. Cuando no, es posible que desee utilizar[: vinv u & v
o en suu & (v :. vinv)
lugar.^:_
es extremadamente útil para algoritmos en los que desea alcanzar la convergencia, como un relleno de inundación o simulaciones.=.
y=:
se puede incrustar en cualquier parte de una frase. Use esto para hacer frases donde la notación tácita no sea suficiente.,
reducciones monádicas en lugar de múltiples cuando reduzca arreglos multidimensionales.fuente
Tenga cuidado con el uso de bucles.
Mientras que J ha estructuras de bucle (
for. do. end.
,while. do. end.
y variaciones), si usted se encuentra usarlos hay una posibilidad de que su algoritmo no está jugando al golf fortalezas de J y que hay un ahorro de caracteres que se harán.^:
La conjunción de poder es tu amigo. Para ejecutar un verbox
veces:Si necesita el resultado de cada iteración en una lista:
También puedes usar
^:
para ejecutar un verbo condicionalmente:Duplique
+:
si^:
el elemento es mayor que 33<]
("0
cambia el rango del verbo para que funcione un elemento a la vez).fuente
(i.x)
ejemplo,f^:(<x)
es decir, es equivalente af^:(i.x)
.Entrada
1!:1[1
tomará una línea de entrada terminada presionando la tecla enter.1!:1[3
tomará una serie de líneas de entrada (terminadas por Ctrl-D en mi Mac, Ctrl-C en Windows).Si está tratando de ingresar números, el uso
".
evaluará la cadena y devolverá una lista de números listos para ser manipulados. Si toma un número pero necesita operar los dígitos individualmente".,.
(gracias al comentario de Jan Dvorak por esto) o"."0
dividirá la cadena en dígitos separados:Si está leyendo en cadenas, la forma más corta de obtener una lista en caja de cadenas separadas es usar
;:
. Esto funciona mejor para cadenas separadas por espacios:fuente
1!:1[2
funcionaría (si acaso)?1!:
página (no soy un experto en J) 2 es la pantalla, por lo que la entrada desde la pantalla no tiene mucho sentido.2
no es válido? No tengo mi computadora J en mí para probarlo en este momento. Donde veo2
, justo debajo de las notas sobre1!:1
, es para1!:2
.".
es rango 1-xx y,.
siempre produce una matriz 2D,".,' ',.
(puntada con espacio, deshilachado y evaluación; 8 caracteres) puede reemplazarse por solo".,.
(deshilachado y evaluación; 4 caracteres).Usando iteración para calcular secuencias
Típicamente, resolver un desafío de secuencia OEIS requerirá usar una de las fórmulas dadas en su página. Algunos de estos se adaptan bien para J, y otros no tanto. Las fórmulas recursivas son sencillas, sin embargo, la iteración podría no ser simple. Un patrón que comencé a usar es
donde
s
es el primer valor de la secuencia,f
es un verbo que calculará el siguiente término dado el término anterior, yn
es el índice basado en cero del término que desea calcular. Este método se basa en el hecho de que al calcular el poder de una díada, el LHS está unido a la díada para formar una nueva mónada, y esa mónada se anida en el valor inicial. La diada dada al adverbio de potencia es un gancho donde(]f)
se le da el índicen
en el LHS y el valor de un término en la secuencias
. El gancho se aplicaráf
ens
como una mónada, y luego ignorarn
a devolver el resultado def s
.Biblioteca estándar
A veces, puede encontrar que J tendrá soporte para un verbo en su biblioteca estándar . Por ejemplo, la mayoría de las operaciones enteras a nivel de bits están vinculadas a nombres que son más cortos que el uso de la llamada primitiva.
Fecha y hora incorporadas también están disponibles.
Rangos
Si tiene un conjunto de valores
[a, b, c]
y desea formar un rango basado en su producto[0, 1, 2, ..., a*b*c-1]
, el enfoque típico sería encontrar su producto y luego formar un rango que podría[:i.*/
costar 6 bytes. Una forma más corta es,@i.
para 4 bytes, ya quei.
puede formar matrices multidimensionales mientras sigue contando, y al aplanarla producirá un rango equivalente.Imprimir continuamente
Una forma tácita de imprimir un valor y continuar usándolo sin un ciclo explícito es
([echo)
para un caso monádico.echo
es un verbo en la biblioteca estándar que imprime sus contenidosstdout
en el mismo formato utilizado en el intérprete. El gancho luego pasa el mismo valor de entrada usando el[
verbo izquierdo .Base 10 dígitos de un entero
¡La forma estándar de adquirir los 10 dígitos básicos de un entero es lo
10#.inv]
que cuesta 8 bytes, demasiado! Una alternativa es convertirlo en una cadena y analizarlo en el rango 0"."0@":
que guarda un byte, pero una forma aún mejor es,.&.":
que guarda otro byte haciendo que el costo final sea de 6 bytes en lugar de 8.fuente
Considere usar una definición explícita en lugar de escribir un verbo tácito; seguro
3 :'
y'
cuesta 5 bytes, pero puede ahorrar mucho@
,@:
y de[:
esa manera.fuente
Algunos trucos (bastante) comunes que he visto
Estoy compartiendo algunas cosas que me han sido útiles. Básicamente, todos estos son consejos que he recibido, pero no tengo créditos para la mayoría.
Suma de una matriz de rango uno
En lugar de usar el
+/@:(FGH)
uso(1#.FGH)
. Esto significa degradar a la base 1, lo que efectivamente significa sumar una matriz. Aunque es más largo que+/
, no requiere una tapa o composición, lo que a menudo lo hace mucho más corto que el uso+/
.Contando verdades finales
Si tiene una lista booleana y desea contar el número de verdades finales, use
#.~
. Vea aquí . La respuesta APL proporciona una buena explicación de cómo funciona esto. De acuerdo, esto solo me ha sido útil dos veces, pero pensé que lo compartiría de todos modos.Debajo (&.)
No es un truco específico, sino solo una sugerencia general: el adverbio
&.
debajo a menudo conduce a soluciones elegantes y (más importante) cortas. Tenlo en cuenta cuando juegues al golf.Muchas veces es útil para desafíos de conversión de base y otros binarios , por ejemplo, este código que elimina el bit más significativo de un número:
}.&.#:
(convertir a la lista de dígitos binarios, eliminar el primer dígito, luego deshacer la conversión a una lista de dígitos binarios y convertir volver al decimal). La solución directa es dos bytes más:#.@}.@#:
.Under también es útil para desafíos en los que necesita trabajar con dígitos decimales, ya que puede usarlos
u&.":
. Por ejemplo, el camino corto que las millas dan para dividir en dígitos decimales se usa en:,.&.":
.Un último ejemplo es encontrar la magnitud de un vector:
+/&.:*:
tenga en cuenta que necesita recopilar todos los resultados de*:
-square con&.:
-under ya que*:
-square es rango cero.fuente
Formas más cortas de meterse con los rangos
A veces, tendrá un código como
<"0 i.3 3
, donde desea aplicar un verbov
en el rangor
. Sin embargo, si usa un sustantivo (como0
), a menudo tendrá que incluir un espacio. Para evitar esto, puede usar otro verbou
de rango equivalente y usaru"v
en su lugar. Por ejemplo, dado que+
tiene rango0 0 0
, podemos usarlo en<"+
lugar de<"0
.Aquí hay una tabla de todos los verbos y sus rangos (que se pueden obtener mediante el uso
v b. 0
):Para usar esta tabla, encuentre el rango deseado
r
en el lado izquierdo, luego elija un verbo apropiadov
del lado derecho. Por ejemplo, si necesito vectorizar un verbov
en profundidad2 _ 2
, entonces encuentro ese rango a la izquierda y elijo%.
desde la derecha. Luego uso env"%.
lugar dev"2 _ 2
.fuente
strings
biblioteca: consejos de golfLa biblioteca de cadenas es muy útil para hacer cualquier cosa con la manipulación de cadenas. Claro, toma
include'strings'
(lo cual es muy costoso, considerando J), pero a veces puede cosechar los beneficios.stringreplace
¿Te encuentras usando el reemplazo de cuerdas? Observe que
A stringreplace B
es lo mismo queB rplc A
.De hecho, así es como
rplc
se implementa:cuts
El verbo
cuts
proporciona así:Entonces, realmente está cortando una cuerda.
fuente
Obtener números del 0 al 4
Si hay una restricción en el uso de números en su código:
0
%_
: uno dividido por infinito.1
#_
: ¿cuántos infinitos?2
#_ _
: dos infinitos.3
verb
: hay un incorporado.4
dyad
: otro incorporado.Obtener números del 10 al 35
Literales Base-Inifinity: 11 :
_bb
, 26 :_bq
etc.fuente
Programación tácita
Lo esencial
Verbo diádico
Verbo monádico
Misceláneos
Trucos
(F x) G (H y)
Solución tácito:
(G~F)~H
; dependiendo de los verbos reales, considere reorganizar los argumentos izquierdo y derecho para eliminar~
.Reemplazos monádico-diádicos
fuente
(G~F)~H
es pura bondad burbujeante!&
es tu amigo, úsalo sabiamentev
es un verbo,n
es un sustantivox
yy
son argumentos izquierdo y derecho, respectivamente.Mónada
&
: Introducir~
dentro del adverbio / cadena de conjunciónUna cadena de adverbio / conjunción se evalúa desde la izquierda. Entonces, algo así
_2&+/\&.>
no funcionará porque se analiza(_2&+)/\&.>
mientras queramos_2&(+/\)&.>
. En este caso, intercambiar la izquierda / derecha de+/\
puede guardar un byte,+/\~&_2&.>
ya que este se analiza como((+/\)~)&_2&.>
. Para ver por qué esto funciona:Pareja
&
: repetirx
tiempos¿Sabías que si le das un argumento
x
a la izquierda&
, la función se aplica ax
vecesy
? Muchos desafíos le piden que realice ciertas operacionesx
tiempos de . Se puede lograr principalmente de dos maneras:^:
sin el operando correctoSi la operación es
v
, entonces sev^:
convierte en un tren adverbio que, cuando se le da un operando izquierdo, se convierte en un verbo monádico. Por lo tantov
, se aplica ay
,x
veces.&
como la conjunción más externaPara usar esto, debe identificar un
n
verbo constante y un verbo diádicou
, de modo quen u y
oy u n
sea equivalente av
. Luego puedes escribirn&u
ou&n
resolver toda la tarea. Esta forma es más efectiva cuando la elección de la constante es obvia, por ejemplo, 3 in3 u:
(convertir caracteres a valores ASCII).Además,
u&n
se prefiere un pocon&u
cuando la estructura más externa deu
es una conjunción o un adverbio (en cuyo cason&u
debería sern&(u)
; puede hacerlo en suu~&n
lugar).Tenga en cuenta que puede colocar la diádica
&
en cualquier lugar de un tren para lograr la repetición de funciones arbitrarias a argumentos arbitrarios, en el mismo sentido que dinámico^:
.fuente