Consejos para jugar golf en CJam


43

CJam es un lenguaje de golf basado en pila inspirado en GolfScript, creado por el aditsu de usuario PPCG .

Entonces, en la línea de otras preguntas de consejos específicos del idioma:

¿Qué consejos generales tienes para jugar al golf en CJam? Por favor, publique un consejo por respuesta.


44
Consulte también Consejos para jugar golf en GolfScript ; los idiomas son lo suficientemente similares como para que muchos de los trucos se puedan adaptar de cualquier manera.
Ilmari Karonen

2
@IlmariKaronen Después de analizar las respuestas en esa pregunta, diría que solo la mitad de ellas se aplican a CJam, debido a diferencias sintácticas o lógicas en los idiomas.
Optimizador

Respuestas:


23

Módulo correcto para números negativos

A menudo es molesto que el resultado de la operación de módulo dé el mismo signo que el primer operando. Por ejemplo, -5 3%da en -2lugar de 1. La mayoría de las veces quieres lo último. La solución ingenua es aplicar el módulo, agregar el divisor una vez y aplicar el módulo nuevamente:

3%3+3%

Pero eso es largo y feo. En lugar de ello, podemos utilizar el hecho de que la indexación de matrices siempre es modular y hace el trabajo correctamente con índices negativos. Así que simplemente convertimos el divisor en un rango y accedemos a eso:

3,=

Aplicado a -5, esto da 1como se esperaba. ¡Y es solo un byte más largo que el incorporado %!

Si el módulo es una potencia de 2, puede guardar otro byte usando arihmética bit a bit (que también es mucho más rápido). Comparar:

32,=
31&

Para el caso especial de 65536 == 2^16otro byte se puede guardar haciendo uso del comportamiento de ajuste del tipo de carácter:

ci

13

Empujar rangos de caracteres concatenados

  • La cadena que contiene todos los dígitos "0123456789"se puede escribir como

    A,s
    
  • Las letras mayúsculas ASCII ( A-Z) se pueden empujar como

    '[,65>
    

    que genera la cadena de todos los caracteres hasta Z , luego descarta los primeros 65 (hasta @ ).

  • Todas las letras ASCII ( A-Za-z) se pueden insertar como

    '[,65>_el+
    

    que funciona como arriba, luego crea una copia, se convierte en minúsculas y se agrega.

    ¡Pero hay una forma más corta de hacerlo!

    Luego, el ^operador que a menudo se pasa por alto (diferencias simétricas para listas) permite crear los mismos rangos mientras se guardan tres bytes:

    '[,_el^
    

    '[,crea el rango de todos los caracteres ASCII hasta Z , _elcrea una copia en minúscula y ^mantiene solo los caracteres de ambas cadenas que aparecen en una pero no en ambas.

    Como todas las letras en la primera cadena son mayúsculas, todas en la segunda son minúsculas y todos los caracteres que no son letras están en ambas cadenas, el resultado en la cadena de letras.

  • El alfabeto RFC 1642 Base64 ( A-Za-z0-9+/) se puede insertar utilizando la técnica anterior y agregando las no letras:

    '[,_el^A,s+"+/"+
    

    Una forma igualmente corta de empujar esta cadena hace uso únicamente de diferencias simétricas:

    "+,/0:[a{A0":,:^
    

    ¿Cómo podemos encontrar la cuerda al principio?

    Todos los rangos de caracteres utilizados ( A-Z, a-z, 0-9, +, /) pueden ser empujados como la diferencia simétrica de a la gama que comienzan en el byte nulo, es decir 'A,'[,^, 'a,'{,^, '0,':,^, '+,',,^y '/,'0,^.

    Por lo tanto, ejecutar :,:^on "A[a{):+,/0"empujará los caracteres deseados, pero no en el orden correcto.

    ¿Cómo encontramos el orden correcto? Fuerza bruta al rescate! El programa

    '[,_el^A,s+"+/"+:T;"0:A[a{+,/0"e!{:,:^T=}=
    

    itera sobre todas las permutaciones posibles de la cadena, aplica :,:^y compara el resultado con la salida deseada ( enlace permanente ).

  • El alfabeto radix-64 utilizado, por ejemplo, por crypt ( .-9A-Za-z) se puede generar utilizando el método anterior:

    ".:A[a{":,:^
    

    Este es el método más corto que conozco.

    Dado que todos los caracteres en la salida deseada están en orden ASCII, no es necesario iterar sobre permutaciones.

  • No todos los rangos de caracteres concatenados se pueden empujar en el orden deseado usando :,:^.

    Por ejemplo, el rango 0-9A-Za-z;-?no se puede impulsar ejecutando :,:^cualquier permutación de "0:A[a{;@".

    Sin embargo, podemos encontrar una variación rotada de la cadena deseada que puede, utilizando el código

    A,'[,_el^'@,59>]s2*:T;"0:A[a{;@"e!{:,:^T\#:I)}=Ip
    

    que imprimirá ( enlace permanente ) lo siguiente:

    10
    0:@[a{A;
    

    Esto significa que

    "0:@[a{A;":,:^Am>
    

    tiene el mismo efecto que

    A,'[,_el^'@,59>]s
    

    que solo se puede usar con una pila vacía sin anteponer a [.


11

¿Evitar {...} {...}?

Suponga que tiene un número entero en la pila. Si es impar, desea multiplicarlo por 3 y agregar 1; de lo contrario, desea dividirlo por 2.

Una declaración if / else "normal" se vería así:

_2%{3*)}{2/}?

Sin embargo, el uso de bloques generalmente no es el camino a seguir, ya que {}{}ya agrega cuatro bytes. ?también se puede usar para seleccionar uno de los dos elementos en la pila:

_2%1$3*)@2/?

Este es un byte más corto.


Bloquear-? con una declaración if vacía siempre es un no-go. Por ejemplo,

{}{2/}?

es dos bytes más largo que

{2/}|

Si en cambio tienes

{2/}{}?

y lo que estás comprobando es un entero no negativo, puedes hacer

g)/

Los nuevos {}&y {}|prácticos, pero a veces problemáticos si no puedes abarrotar la pila.

Aún así, en el caso de

_{…}{;}?

puedes usar una variable temporal en su lugar:

:T{T…}&

1
!)/y g)/son más cortos en los ejemplos.
jimmy23013

11

Cambiar declaraciones

CJam no tiene declaraciones de cambio. Anidadas si las declaraciones funcionan igual de bien, pero {{}{}?}{}?ya tiene 12 bytes de longitud ...

Si podemos transformar la condición en un entero pequeño, no negativo, podemos transformar todas las declaraciones de caso en una cadena delimitada y evaluar el resultado correspondiente.

Por ejemplo, si queremos ejecutar code0si el número entero de la pila es 0 , code1si es 1 y code2si es 2 , podemos usar

_{({code2}{code1}?}{;code0}?

o

[{code0}{code1}{code2}]=~

o

"code0 code1 code2"S/=~

S/divide la cadena en ["code0" "code1" "code2"], =extrae el fragmento correspondiente y ~evalúa el código.

Haga clic aquí para ver las declaraciones de cambio en acción.

Finalmente, como lo sugieren @ jimmy23013 y @RetoKoradi, podemos acortar aún más el cambio en algunos casos. Say code0, code1y code2tienen longitudes L 0 , L 1 y L 2 , respectivamente.

Si L 0 = L 1 ≥ L 2

"code0code1code2"L/=~

se puede usar en su lugar, donde Les L 0 . En lugar de dividirse en un delimitador, /divide la cadena en trozos de igual longitud aquí.

Si L 0 ≥ L 1 ≥ L 2 ≥ L 0 - 1 ,

"cccooodddeee012">3%~

se puede usar en su lugar. >elimina 0, 1 o 2 elementos del comienzo de la cadena y 3%extrae cada tercer elemento (comenzando por el primero).


Para el último ejemplo, ¿tiene alguna ventaja "code0code1code2"5/=~? Me parece mucho más sencillo, y tiene la misma longitud.
Reto Koradi

@RetoKoradi Si todos los fragmentos tienen la misma longitud, no hay ventaja. Para diferentes longitudes, su método puede ser más corto y más largo que el método de módulo.
Dennis

11

Golf común array y valores de cadena

Hay ciertas series o cadenas cortas que surgen de vez en cuando, por ejemplo, para inicializar las cuadrículas. Ingenuamente, estos pueden costar 4 o más bytes, por lo que vale la pena buscar operaciones con valores integrados que den el mismo resultado. Especialmente la conversión de bases suele ser útil.

  • [0 1]se puede escribir como 2,.
  • [1 0]puede escribirse como YYb(es decir, 2 en binario).
  • [1 1]se puede escribir como ZYb(es decir, 3 en binario).
  • La matriz [[0 1] [1 0]]se puede escribir como 2e!.
  • [LL] se puede escribir como SS/(dividiendo un solo espacio por espacios).
  • "\"\""se puede escribir como L`.
  • "{}"se puede escribir como {}s.

Este último se puede extender a los casos en que desea que todos los tipos de paréntesis guarden otro byte:

  • "[{<()>}]"se puede escribir como {<()>}a`.
  • "()<>[]{}"se puede escribir como {<()>}a`$.

Especialmente el truco de conversión de base puede ser útil para tener en cuenta para algunos casos oscuros que aparecen de vez en cuando. Por ejemplo [3 2], sería E4b(14 en la base 4).

En casos aún más raros, incluso puede encontrar mfútil el operador de factorización . Por ejemplo, [2 7]es Emf.

Siéntase libre de ampliar esta lista si encuentra otros ejemplos.


10

Despejando la pila

Si solo desea borrar toda la pila, envuélvala en una matriz y revísela:

];

Lo que es un poco más complicado es, si has hecho muchos cálculos, pero solo quieres mantener el elemento de la pila superior y descartar todo lo que está debajo. El enfoque ingenuo sería almacenar el elemento superior en una variable, borrar la pila, empujar la variable. Pero hay una alternativa mucho más corta: envolver la pila en una matriz y extraer el último elemento:

]W=

(Gracias a Optimizer que me mostró esto el otro día).

Por supuesto, si solo hay dos elementos en la pila, \;es más corto.


\;solo aparecería el elemento debajo de los TOS. Quiso decir ;;?
CalculatorFeline

1
@CalculatorFeline la segunda mitad de la respuesta se trata de borrar todo menos los TOS.
Martin Ender

9

e y poderes de diez

Como en otros tantos idiomas, puedes escribir en 1e3lugar de 1000en CJam.

Esto funciona para bases no enteras e incluso para exponentes no enteros también. Por ejemplo, 1.23e2empuja 123.0 y 1e.5empuja 3.1622776601683795 (raíz cuadrada de 10 ).

Lo que no es obvio de inmediato es que en 1e3realidad son dos tokens:

  • 1empuja el entero 1 en la pila.

  • e3lo multiplica por 1000 .

¿Por qué es eso importante?

  • Puedes invocar e<numeric literal>algo que ya está en la pila.

    2 3 + e3 e# Pushes 5000.
    
  • Puede mapear e<numeric literal>sobre una matriz.

    5 , :e3  e# Pushes [0 1000 2000 3000 4000].
    

9

Normas euclidianas

La forma directa de calcular la norma euclidiana de un vector, es decir, la raíz cuadrada de la suma de los cuadrados de sus elementos, es

2f#:+mq

Sin embargo, hay un camino mucho más corto.

mh, el operador de hipotenusa, saca dos enteros a y b de la pila y empuja sqrt (a 2 + b 2 ) .

Si tenemos un vector x: = [x 1 … x n ], n> 1 en la pila, :mh(reducir por hipotenusa) lograremos lo siguiente:

  • Primero se empujan x 1 y x 2 y mhse ejecuta, dejando sqrt (x 1 2 + x 2 2 ) , en la pila.

  • Luego, x 3 se empuja y mhse ejecuta nuevamente, dejando
    sqrt (sqrt (x 1 2 + x 2 2 ) 2 + x 3 2 ) = sqrt (x 1 2 + x 2 2 + x 3 2 ) en la pila.

  • Después de que x n ha sido procesado, nos queda sqrt (x 1 2 +… x n 2 ) , la norma euclidiana de x .

Si n = 1 y x 1 <0 , el código anterior producirá un resultado incorrecto. :mhztrabaja incondicionalmente (Gracias a @ MartinBüttner por señalar eso).

He usado este truco por primera vez en esta respuesta .


2
Por supuesto, esto tiene implicaciones para el análisis numérico de su programa ...
Peter Taylor

8

Convierte desde base n con una lista de números mayor que n

CJam convierte una lista en un número con esta fórmula: A 0 * n l + A 1 * n l-1 + A 2 * n l-2 + A l * n 0 (con no negativo n). nes la base y les la longitud de la lista. Esto significa que A i puede ser cualquier número entero, que no tiene que estar en el rango de [0,n).

Algunos ejemplos:

  • 0bextrae el último elemento y lo convierte en entero. Funciona como W=iy guarda un byte si no fuera entero. Pero todo lo demás en la lista también debe poder convertirse en entero.
  • 1bdevuelve la suma Funciona como :i:+y guarda dos bytes si no fueran enteros. También funciona con listas vacías mientras :+que no.
  • [i{_1&9 32?_@\m2/}16*;]W%:cconvierte un carácter en una cadena de finales de línea y pestañas, que se pueden volver a convertir con 2bc. Sin embargo, la función de codificación no es fácil de jugar en un programa de código de golf. Pero generalmente no necesitas eso.
  • Puede usar el siguiente código para convertir una cadena a caracteres Unicode que no estén en 16 bits, que se pueden volver a convertir 2A#b128b:c. (Las explicaciones se agregarán más tarde. O tal vez escriba una nueva versión más adelante).

    128b2A#b         " Convert to base 1024. ";
    W%2/)W%\:+       " Convert to two base 1024 digit groups. ";
    [0X@
    {
      _54+
      @I+_Am>@\-
      _Am<@+ 0@-@1^
    }fI
    ]);)
    @\+[~+]2A#b_2G#<!{2A#b}*
    \W%+:c
    

El método similar funciona con cualquier conjunto de nenteros que tengan diferentes valores de mod n, si puede encontrar alguna forma de deshacerse del dígito más significativo.


8

Utilizando $como ternario si

Cuando no le importa perder memoria, es decir, dejar elementos no utilizados en la pila con los que luego borrará ];, el operador de copia $puede ser un sustituto útil del operador ternario ?.

? funciona bien si logra calcular la condición antes de presionar los dos elementos para elegir, pero la mayoría de las veces, la condición realmente depende de esos elementos, y tenerla encima de ellos resulta mucho más natural.

Si tienes A B Cen la pila, puedes ejecutar

!$

en lugar de

\@?

copiar Bsi Ces verdad y de Aotra manera.

Si Ces un booleano real ( 0o 1), puede ejecutar

$

en lugar de

@@?

copiar Asi Ces verdad y de Botra manera.


En retrospectiva, este es un truco bastante obvio, pero nunca lo había pensado antes. Lo he usado por primera vez en esta respuesta .
Dennis

7

Mapa de listas anidadas

Digamos que tienes una lista anidada, como una matriz:

[[0 1 2][3 4 5][6 7 8]]

O una serie de cadenas:

["foo""bar"]

Y desea asignar un bloque al nivel anidado (es decir, aplicarlo a cada número o cada carácter). La solución ingenua es anidada %:

{{...}%}%

Sin embargo, en realidad puede empujar el bloque interno sobre la pila y luego usarlo f%. fes "mapear con parámetro adicional", por lo que se mapeará %en la lista externa, usando el bloque como segundo parámetro:

{...}f%

Guarda dos bytes.

Otro buen truco para hacer algo como for (i=0; i<5; ++i) for (j=0; j<5; ++j) {...}es

5,_f{f{...}}

El exterior se fasignará al primer rango, proporcionando el segundo rango como un parámetro adicional. Pero ahora, si lo usa de fnuevo, solo el elemento de la pila superior es una matriz, por lo que fasigna el bloque interno a ese, proporcionando la "variable de iteración" externa como un parámetro adicional. Esto significa que el bloque interno se ejecuta con iy jen la pila.

Tiene la misma cantidad de caracteres que simplemente mapear un bloque en un producto cartesiano (aunque este último se acorta si necesita los pares como matrices):

5,_m*{~...}%

La diferencia es que esta versión produce una única matriz de resultados para todos los pares, mientras que el doble fproduce una lista anidada, que puede ser útil si desea almacenar los resultados en una cuadrícula, siendo las coordenadas las variables iteradoras.

Gracias a Dennis por mostrarme este truco.

0.6.4 Actualizar

fy :ahora han sido inmensamente mejorados al tomar cualquier otro operador, incluidos ellos mismos. Esto significa que ahora puede guardar aún más bytes. La asignación de un operador a una lista anidada se hizo aún más corta ahora:

{:x}%
{x}f%
::x

Sin embargo, esto realmente no ayuda con la asignación de bloques en listas anidadas.

En cuanto a la aplicación de bloques u operadores al producto cartesiano, esto también se acortó ahora, tanto para los bloques como para los operadores:

5,_f{f{...}}
5,_ff{...}

5,_f{fx}
5,_ffx

Lo bueno es que ahora puedes anidarlos. Por lo tanto, puede aplicar un operador con la misma facilidad al tercer nivel en una lista:

:::x

O un bloque con algunos trucos:

{...}ff%

Gran actualización Pero todavía no hay f~...
jimmy23013

@ user23013 fespera un operador binario, ~es unario; quizás quisiste :~? Además, podemos discutir esto en el chat
aditsu

¿Me falta algo sobre esta actualización 0.6.4? Todavía recibo mensajes de error haciendo esos trucos, como Unhandled char after ':': :( enlace )
Runer112

2
@ Runer112 funciona para mí. Asegúrese de volver a cargar correctamente (es decir, no desde la memoria caché). Dependiendo de su navegador, Ctrl + F5 debería funcionar.
Martin Ender

@ MartinBüttner De hecho, fue causado por el almacenamiento en caché tonto. Gracias.
Runer112

7

Operadores vectorizados para arte ASCII

Para muchos desafíos artísticos ASCII, es útil generar dos patrones diferentes para superponerlos más tarde. Los operadores vectorizados pueden ser muy útiles para lograr diferentes tipos de superposiciones.

Una propiedad útil de la vectorización del operador es que el operador solo se ejecuta una vez para cada elemento de la cadena / matriz más corta, mientras que los elementos de la más grande que no tienen contrapartes permanecen intactos.

  • .e<

    El operador mínimo e<trabaja para pares de cadenas, caracteres, matrices y enteros; saca dos elementos de la pila y empuja la parte inferior hacia atrás.

    Dado que un espacio tiene un punto de código más bajo que todos los demás caracteres ASCII imprimibles, .e<se puede usar para "borrar" partes de un patrón generado:

    "\/\/\/\/\/" "    " .e<
    
    e# This pushes "    \/\/\/".
    

    Para un ejemplo completo, vea mi respuesta a Me Want Honeycomb .

  • .e>

    El operador máximo e>funciona como el operador mínimo, con el resultado opuesto.

    Nuevamente, debido al bajo punto de código del espacio, .e>puede usarse para insertar un patrón de caracteres imprimibles en un bloque de espacios:

    [[" " " " " " " "] [" " " " " " " "]][["+" "" "-" ""]["" "*" "" "/"]] ..e>
    
    e# This pushes [["+" " " "-" " "] [" " "*" " " "/"]].
    

    Para un ejemplo completo, vea mi respuesta a Seven Slash Display .

  • .e&

    El operador lógico AND e&empuja su argumento izquierdo si es falso y su argumento derecho de lo contrario.

    Si ninguno de los patrones contiene elementos falsos, esto puede usarse para imponer incondicionalmente un patrón sobre otro:

    "################" " * * * *" .e&
    
    e# This pushes " * * * *########".
    

    Para ver un ejemplo completo, vea mi respuesta para Imprimir la bandera estadounidense. .

  • .e|

    El operador lógico OR e|se puede usar como se indicó anteriormente, con el orden inverso de los argumentos:

    " * * * *" "################" .e|
    
    e# This pushes " * * * *########".
    

6

Use &para verificar si un artículo está en una lista

por

1 [1 2 3] #W>
1 [1 2 3] #)

Puedes usar

1 [1 2 3] &,
1 [1 2 3] &

en cambio, que devuelve 0/1 y truthy / falsey respectivamente.


6

z y matrices no rectangulares

El operador zip ztranspone las filas y columnas de una matriz A bidimensional 1 , cuyos elementos también pueden ser iterables.

Para matrices no rectangulares, a diferencia de las zipfunciones integradas en, por ejemplo, Python (trunca las filas a la misma longitud) o Ruby ( nilrellena las filas con ), CJam simplemente convierte las columnas de la matriz en filas, ignorando sus longitudes y brechas.

Por ejemplo, comprimir la matriz

[
  [1]
  [2 4]
  [3 5 6]
]

es equivalente a comprimir la matriz

[
  [1 4 6]
  [2 5]
  [3]
]

o la matriz

[
  [1]
  [2 4 6]
  [3 5]
]

mientras las tres acciones empujan

[
  [1 2 3]
  [4 5]
  [6]
]

en la pila

Si bien esto significa que zno es una involución (que sería útil en ocasiones), tiene algunas aplicaciones.

Por ejemplo:

  • Podemos alinear las columnas de una matriz a la parte superior (es decir, convertir la primera matriz en la segunda) comprimiendo dos veces:

    zz
    
  • Se pueden usar modificaciones menores del método anterior para problemas similares.

    Por ejemplo, para alinear las columnas de una matriz con la parte inferior (es decir, para convertir la segunda matriz en la primera), podemos comprimir dos veces con el orden de fila invertido:

    W%zzW%
    
  • Dada una serie de cadenas, podemos calcular la longitud de la cadena más larga de esta manera:

    :,:e>
    

    Sin embargo, al comprimir y calcular el número de filas del resultado, podemos guardar tres bytes:

    z,
    

1 Si alguna de las "filas" de A no es iterable, las ztrata como singletons, por lo que la compresión funciona para matrices arbitrarias.


1
Es una forma diferente de visualizar lo mismo, pero para mí el comportamiento es mucho más lógico si imagino zconvertir columnas en filas, mientras se omiten los valores vacíos. En el ejemplo, la primera columna en la entrada es 1, 2, 3, la segunda columna es 4, 5 (se omite la posición vacía), y la tercera columna es 6. Estas son las filas del resultado.
Reto Koradi

@RetoKoradi Esa es una forma mucho mejor de describirlo.
Dennis

6

Excepciones

Todas las excepciones son fatales en CJam. Como la salida a STDERR se ignora por defecto , podemos usar esto para nuestra ventaja.

Todos los operadores en CJam trabajan sacando cero o más elementos de la pila, realizan alguna tarea y empujan cero o más elementos en la pila. Se producen excepciones mientras se realiza la tarea, por lo que aún aparecen los elementos, pero no se empuja nada a cambio.

Aquí hay algunos casos de uso:

  • Despejando una pequeña pila

    Para borrar una pila que contiene dos elementos, @se puede usar. @intenta reventar tres elementos de la pila, pero falla después de reventar el segundo.

    Cualquier otro operador que muestre tres elementos serviría para el mismo propósito.

    Véalo en acción aquí .

  • Eliminar dos o tres elementos de la pila

    Cualquier operador que no esté implementado para estos elementos en particular puede usarse para extraer dos o tres elementos de la pila justo antes de salir.

    Para reventar dos elementos, bfunciona si uno de ellos es un personaje o ninguno de ellos es un número entero.

    Para reventar tres elementos, tfunciona si ninguno de los dos más inferiores es iterable, el más inferior está vacío o ninguno de ellos es un entero.

  • Saliendo de un bucle

    En ocasiones, necesitamos salir de un bucle cuando un entero se convierte en cero o una cadena se vuelve demasiado corta. En lugar de probar estas condiciones, si las operaciones involucradas fallan por cero, la cadena vacía o los singletons, simplemente podemos dejar que el programa siga su curso natural.

    Para ver un ejemplo de aritmética, consulte aquí .

    Para ver un ejemplo de cadenas, vea aquí .

  • Ejecución condicional

    Si el código fuente no se debe ejecutar para ciertos tipos de entrada, a veces podemos usar un operador que falla ese tipo de entrada.

    Por ejemplo, ifallará para cadenas que no se evalúan como un número entero y ewfallará para cadenas de longitud 0 o 1.

    Véalo en acción aquí .


5

Max / Min de una matriz

¡Aquí hay uno para empezar!

Cuando necesita encontrar el número máximo o mínimo de una matriz, la forma más fácil y más pequeña es ordenar la matriz y luego extraer el primer o el último elemento.

Entonces, si la matriz está en variable A

A$W=

es el máximo y

A$0=

Es el mínimo.

Obtener ambos al mismo tiempo también es posible

A$)\0=

Esto puede parecer obvio después de leer, pero el primer intento de cualquiera tiende a ir hacia el uso e<o e>mediante la iteración a través de la matriz, que es como

A{e<}*

que es 2 bytes más, e incluso más si quieres max y min.


Por supuesto, si no le importa el resto de la matriz que queda en la pila, puede usar (y en )lugar de 0=y W=.
Martin Ender

Ahora hay :e<y:e>
aditsu

@aditsu Sin embargo, no son más cortos que la punta de arriba.
Optimizador

5

Use una marca de tiempo para números grandes

Si necesita un número muy grande pero arbitrario, generalmente usará la notación científica como 9e9o elevará una de las grandes variables incorporadas a una potencia similar, como KK#. Sin embargo, si no le importa cuál es el número real, y no necesita ser siempre el mismo (por ejemplo, como el límite superior para un número aleatorio), puede hacerlo en dos bytes usando

es

en lugar. Esto proporciona la marca de tiempo actual en milisegundos y es del orden de 10 12


3
También tenga en cuenta que si desea un número arbitrario grande y desea descartar un número positivo juntos, puede usarlo e9.
jimmy23013

5

Comprobando que dos cadenas / matrices no son iguales

A veces, desea un valor verdadero cuando dos cadenas o matrices no son iguales, y un valor falso si lo son. La solución obvia son dos bytes:

=!

Verifique la igualdad e invierta el resultado. Sin embargo, bajo ciertas condiciones puedes usar

#

Cuando #se aplica a dos matrices, en realidad busca la segunda matriz como una submatriz de la primera (y le da el índice donde comienza la submatriz). Entonces, si las dos matrices son iguales, la submatriz se encontrará justo al comienzo y dará 0, lo cual es falso. Pero si no se puede encontrar la segunda matriz, dará -1cuál es la verdad.

La razón por la que necesitamos alguna condición adicional en las dos matrices es que esto también produce un valor falso si la segunda matriz es un prefijo no trivial de la primera, por ejemplo:

"abc""ab"#

da 0aunque las cuerdas no sean las mismas. La condición más simple que descarta este caso es si sabe que ambas matrices tendrán la misma longitud; en ese caso, si una es un prefijo de la otra, sabrá que son iguales. Pero en circunstancias específicas puede haber condiciones más débiles que también son suficientes. Por ejemplo, si sabe que las cadenas están ordenadas, un prefijo siempre será la primera cadena, no la segunda.


5

c y enteros de 16 bits

Para agregar (o restar) enteros de 16 bits sin signo con el ajuste adecuado, puede usar +65536%o +2G#%.

Sin embargo,

+ci

Es mucho más corto. Los personajes se envuelven alrededor de 65536 , por lo que lanzar a Character ( c) luego a Long ( i) tiene un efecto similar a 65536%, con el beneficio adicional de que el resultado no será negativo.

El mismo truco se puede usar para empujar 65535 :

Wci

4

Conjuntos de potencia

Digamos que tiene una matriz y desea una matriz con todos los subconjuntos posibles de esa matriz. El truco es comenzar con una matriz vacía y luego, para cada elemento, duplicar los subconjuntos que ya tienes y agregarles el nuevo elemento (manteniendo el resultado anterior donde no se agregó el elemento ). Tenga en cuenta que necesita inicializar la pila con el caso base, es decir, una matriz que contiene solo una matriz vacía: Esto podría verse así:

[1 2 3 4 5]La\{1$f++}/

Lo bueno de esto es que puede ejecutar inmediatamente algunos cálculos en el subconjunto, potencialmente sin caracteres agregados. Digamos que quiere los productos de todos los subconjuntos. En ese caso, el caso base es una matriz que contiene 1, y en cada paso, toma la lista anterior de posibles productos, la duplica y multiplica todo en el duplicado por el nuevo elemento:

[1 2 3 4 5]1a\{1$f*+}/

4

Compruebe si los elementos de una lista son todos iguales

Creo que esto también vale la pena mencionar. Utilizar:

)-

Devuelve verdadero si no es todo lo mismo, o una lista vacía si es lo mismo. Errores si la lista está vacía.

En caso de que el elemento extraído pueda ser una matriz (o cadena) en sí:

)a-

Use !o !!para obtener valores booleanos. En caso de que el elemento extraído pueda ser una matriz, y haya a lo sumo dos tipos de elementos diferentes, y desee que sea 1, si no todos iguales, esto es más corto:

_|,(

4

0= para cuerdas

Para recuperar el primer elemento de una matriz, debe usar 0=(o (, si no le importa, dejar el resto de la matriz en la pila).

Sin embargo, si esa matriz es una cadena, la conversión al carácter es suficiente.

Ejemplo

"xyz"c e# Pushes 'x.

No veo por qué CJam no solo permite cextraer el primer elemento de cualquier matriz, lo que sería más útil y consistente.
Esolanging Fruit

4

Rotación de una matriz (o la pila) una unidad hacia la izquierda

CJam tiene el operador rotar a la izquierdam< , que normalmente es lo que debe usar para rotar una matriz un número arbitrario de unidades a la izquierda.

En algunos casos, también puede usar (+para cambiar y agregar:

[1 2 3]       (+ e# Pushes [2 3 1].
[[1] [2] [3]] (+ e# Pushes [[2] [3] 1].

El segundo ejemplo no funcionó porque el primer elemento de la matriz también es iterable, por lo que se +concatena en lugar de agregarse.

Además, si desea volcar la matriz girada en la pila, puede usar :\(reducir mediante intercambio) incondicionalmente:

[1 2 3]       :\ e# Pushes 2 3 1.
[[1] [2] [3]] :\ e# Pushes [2] [3] [1].

Mientras no tengas una apertura [, este truco también se puede usar para rotar toda la pila, es decir, para llevar el elemento de la pila más inferior a la parte superior:

]:\

3

Imprimir una lista y limpiar la pila

Digamos que su pila tiene una lista de cadenas / números / etc. en la parte superior y algunos otros elementos adicionales debajo. es decir

123 "waste" ["a" "b" "rty" "print" "me" "please"]

Ahora solo le interesa imprimir la última lista, así que

S*]W=

que salidas

a b rty print me please

Lo que parece realmente inteligente, ya que usamos el truco de limpieza de la pila y solo imprimimos la lista unida con espacios (que a veces puede no ser la forma deseada de imprimir una lista).

¡Esto se puede jugar más al golf!

p];

¡Eso es 2 bytes más corto !

y si solo tienes 1 elemento en la pila además de la lista, ¡es aún más corto!

p;

Lo pbueno de esto es que elimina el elemento más superior de la pila, lo enrosca (también agrega una nueva línea al final) e imprime en STDOUT al instante, sin esperar a que se complete el código.

Entonces el código anterior saldrá

["a" "b" "rty" "print" "me" "please"]

¡cuál es la representación exacta de una lista cuando estaba en la pila!


3

Productos cartesianos o todas las combinaciones posibles de dos o más conjuntos

CJam tiene una calculadora de producto cartesiano incorporada m*que toma las dos primeras listas / cadenas en la pila y crea todos los pares posibles a partir de ella. Por ejemplo

[1 2 3 4]"abc"m*

hojas

[[1 'a] [1 'b] [1 'c] [2 'a] [2 'b] [2 'c] [3 'a] [3 'b] [3 'c] [4 'a] [4 'b] [4 'c]]

como la pila

Pero, ¿qué sucede si desea todas las combinaciones posibles de más de 2 listas / cadenas? Usas m*eso muchas veces? Por ejemplo

[1 2 3 4][5 6]"abc"m*m*

dejará lo siguiente en la pila

[[1 [5 'a]] [1 [5 'b]] [1 [5 'c]] [1 [6 'a]] [1 [6 'b]] [1 [6 'c]] [2 [5 'a]] [2 [5 'b]] [2 [5 'c]] [2 [6 'a]] [2 [6 'b]] [2 [6 'c]] [3 [5 'a]] [3 [5 'b]] [3 [5 'c]] [3 [6 'a]] [3 [6 'b]] [3 [6 'c]] [4 [5 'a]] [4 [5 'b]] [4 [5 'c]] [4 [6 'a]] [4 [6 'b]] [4 [6 'c]]]

Tenga en cuenta que los productos siguen siendo pares, donde uno de los elementos es un par en sí. Esto no se espera y queremos combinaciones planas.

Hay una manera fácil de hacer eso. Simplemente ajuste todas las listas que desee para su producto cartesiano en una matriz, cree productos cartesianos por pares y aplánelo cada vez:

[1 2 3 4][5 6]"abc"]{m*{(+}%}*

Esto deja

[['a 5 1] ['b 5 1] ['c 5 1] ['a 6 1] ['b 6 1] ['c 6 1] ['a 5 2] ['b 5 2] ['c 5 2] ['a 6 2] ['b 6 2] ['c 6 2] ['a 5 3] ['b 5 3] ['c 5 3] ['a 6 3] ['b 6 3] ['c 6 3] ['a 5 4] ['b 5 4] ['c 5 4] ['a 6 4] ['b 6 4] ['c 6 4]]

en la pila

¿Quieres mantener el orden? , simplemente cambie antes de volver a agregar el elemento emergente a la matriz. es decir

{m*{(\+}%}*

¿Quieres solo permutaciones?

{m*{(+$}%_&}*

¿Quieres solo elementos únicos en las combinaciones?

{m*{(+_&}%}*

Eso es todo amigos. por ahora .


1
Ahora también puede hacerlo ]:m*:e_, con cualquier número de matrices
2015

3

Operando en cuerdas

A veces, si está trabajando con una estructura de datos compleja, mientras que los elementos que contiene son simples, la conversión a cadenas puede ayudar.

Por ejemplo, si desea obtener el primer o el último elemento en una matriz 2D de bits, y no le importa el tipo devuelto, sA<guarda un byte de 0=A<o :+A<.

O si desea modificar algunos bits en la entrada, puede modificar la cadena antes de evaluarla.

O si tiene esta estructura y desea convertirla en una lista simple:

[[[[[[[[[1]2]3]4]5]6]7]8]9]

Puedes hacerlo con muchos personajes de otras maneras:

[a{~)\}h;]W%

Pero puede ser mucho más corto con cadenas:

s:~

Es más corto incluso si puede tener números con más de un dígito:

[`La`-~]

O:

`']-~]

Si no necesita otra matriz que contenga muchas de esas matrices.


Hay e_ahora
aditsu

@aditsu Vea esta respuesta y comentario . A veces stodavía funciona mejor.
jimmy23013

Claro, cuando puedes trabajar con una cadena directamente, es más corta.
aditsu

3

Usando en Nlugar deLa

En muchos casos, necesita algo inicializado en una matriz que contenga una matriz vacía como su único elemento, que es La, aparentemente, innecesariamente 1 byte más.

En muchos casos, también debe agregar una nueva línea después de cada elemento antes de imprimir, que sería algo así como Noo N*.

Pero si ambas son ciertas, a veces puede descubrir que puede inicializar la matriz con N, que tiene el carácter de nueva línea como su único elemento. Asegúrese de anteponer solo cosas a los elementos en el resto de su código, y lo primero a anteponer es siempre un carácter o una matriz. O solo agregue, si una nueva línea principal es aceptable y eso la hace más corta.

A veces Stambién funciona si necesita separar la salida con espacios.

En casos más raros, el elemento inicial tiene que ser una cadena. Pero aún puede usar lo Naque podría ser más corto que agregar la nueva línea después.


2

División en uno o más casos

Digamos que tiene una cadena "abbcdbbfghbdbb"y desea dividirlab

"abbcdbbfghbdbb"'b/

Esto deja en la pila:

["a" "" "cd" "" "fgh" "d" "" ""]

¿Notas las cadenas vacías? Esos están allí porque dos bestaban juntos y no había nada entre ellos. A veces, quieres evitar esto. Puedes hacer esto por

"abbcdbbfghbdbb"'b/La-

o filtrar cadenas vacías

"abbcdbbfghbdbb"'b/{},

pero eso es 3 bytes adicionales.

Un operador poco menos conocido para este caso de uso particular es %. Además de hacer mod y mapa y dividir en función del número ( "abcd"2%= "ac"), %también se puede dividir en cadenas / matrices. Entonces, para el caso de uso anterior:

"abbcdbbfghbdbb"'b%

se ira

["a" "cd" "fgh" "d"]

en la pila

Gracias por @ user23013 por señalar esto en una de mis respuestas hoy.


Creo que esto debería llamarse "también aprende GolfScript", que tiene mejores ejemplos en la documentación.
jimmy23013

@ user23013 pero nunca estamos seguros de qué es similar a GS y qué no.
Optimizador

2

Use doblar / reducir como infijo foreach

Tenemos :xcomo una abreviatura de {x}%y o {x}*(dependiendo de si xes unario o binario). Desafortunadamente, no hay un operador infijo equivalente para acortar {x}/. Sin embargo, muy a menudo cuando lo hacemos {x}/, en xrealidad es un operador binario que modifica repetidamente el elemento que se encuentra debajo de la pila. Si ese es el caso, y dicho elemento no es una matriz, podemos guardar un byte abusando de fold / reduce como foreach:

5 [1 2 3 4]{-}/  e# Gives -5
5 [1 2 3 4]+:-

Esto funciona porque doblar siempre deja el primer elemento intacto. Desafortunadamente, no guarda un byte, cuando el elemento modificado es una matriz, porque agregarlo lo desenvolvería. Sin embargo, a veces tiene la suerte de que su matriz ya contiene ese elemento en la parte delantera, en cuyo caso se debe tener en cuenta la reducción (en lugar de eliminar manualmente el elemento antes de usarlo {}/en el resto).


2

imprimir e imprimir

Cjam tiene printoperador: o. Funciona, pero la pila se imprime inmediatamente después de que se haya ejecutado todo el código. Puede detenerlo si borra la pila al final del programa. Simplemente ponga esto al final:

];

Para imprimir puedes usar oNoo p(funciona como `oNo)


3
Hay una gran diferencia entre oy p. pcomienza convirtiendo el elemento a imprimir en una representación de cadena inequívoca. pes equivalente a ejecutar ​`oNo.
Dennis
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.