Escribir un programa que genere su nivel de espejo

31

Hay 95 caracteres ASCII imprimibles :

 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~

En la fuente Consolas (el bloque de código Stack Exchange predeterminado), algunos de los caracteres tienen espejos alrededor de un eje vertical de simetría:

  • Estos pares de personajes son espejos el uno del otro: () [] {} <> /\
  • Estos personajes son espejos de sí mismos: ! "'*+-.8:=AHIMOTUVWXY^_ovwx|(Tenga en cuenta que el espacio es uno).
  • Estos no tienen espejos: #$%&,012345679;?@BCDEFGJKLNPQRSZ`abcdefghijklmnpqrstuyz~

( i, l, 0, #, Y, probablemente, otros personajes son sus propios espejos en algunas fuentes pero me quedo con las formas Consolas).

Se dice que una cadena es un espejo de sí misma si está hecha con solo los 39 caracteres espejo , dispuestos de tal manera que la cadena tenga una línea de simetría vertical central. Entonces ](A--A)[es un espejo de sí mismo pero ](A--A(]no lo es.

Escriba un programa de longitud uniforme de una línea que sea un espejo de sí mismo. Cuando se le han agregado N copias de su mitad izquierda y se le han agregado N copias de su mitad derecha, debería generar N + 1. N es un entero no negativo.

Por ejemplo, si el programa era ](A--A)[(mitad izquierda: ](A-mitad derecha:) -A)[, entonces:

  • Correr ](A--A)[debería dar salida 1. (N = 0)
  • Correr ](A-](A--A)[-A)[debería dar salida 2. (N = 1)
  • Correr ](A-](A-](A--A)[-A)[-A)[debería dar salida 3. (N = 2)
  • Correr ](A-](A-](A-](A--A)[-A)[-A)[-A)[debería dar salida 4. (N = 3)
  • . . .
  • Correr ](A-](A-](A-](A-](A-](A-](A-](A-](A-](A--A)[-A)[-A)[-A)[-A)[-A)[-A)[-A)[-A)[-A)[debería dar salida 10. (N = 9)
  • etc.

Reglas

  • Salida a stdout o la alternativa más cercana a su idioma. Puede haber una nueva línea final opcional. No se debe tomar ninguna entrada.
  • El proceso debería funcionar teóricamente para N hasta 2 15 -1 o más, dada la suficiente memoria y potencia de cálculo.
  • Se requiere un programa completo, no solo un comando REPL .

El programa inicial más corto (caso N = 0) en bytes gana.

Pasatiempos de Calvin
fuente
En algunas fuentes, también #es su propia versión, pero, tienes razón, no en consolas.
SuperJedi224
1
¿Está permitido usar respuestas? En otras palabras: ¿deberíamos escribir un programa válido completo o una expresión es suficiente? Estoy pensando en la entrada de Haskell que funcionaría cuando se ejecuta en ghci pero no es un programa completo válido.
Bakuriu
@Bakuriu Se requiere un programa completo. La respuesta de Haskell no es válida.
Calvin's Hobbies
44
¿Por qué no son espejos 'b' y 'd' entre sí? Hace que mi plan sea imposible: P
Thijs ter Haar
1
@ThijsterHaar En realidad no lo consideré, pero parece que sus formas de Consolas son un poco diferentes, lo siento: P
Calvin's Hobbies

Respuestas:

20

Pip, 12 8 4 bytes

¡Ahora con un 66% menos de bytes!

x++x
  • xes una variable, preinicializada a "". En contexto numérico, esto se convierte 0.
  • La primera mitad, sin la final +, hace una expresión de la forma x+x+...+x. Esta es una declaración válida que no hace nada.
  • La segunda mitad, incluida la final +de la primera mitad, hace una expresión de la forma ++x+x+...+x. ++xincrementa xa 1, y el resto se agrega N veces. Debido a que las expresiones se evalúan de izquierda a derecha en Pip, se garantiza que el incremento ocurra primero, y el resultado es igual al número de niveles espejo.
  • Al final, el valor de esta expresión se imprime automáticamente.

Desafortunadamente, Pip no procesa bien grandes expresiones: esta solución causa un maximum recursion depth exceedederror para N por encima de 500 más o menos. Aquí hay una solución anterior que no lo hace, para 8 bytes :

x++oo++x

Más sobre Pip

DLosc
fuente
OK, a menos que alguien publique una respuesta de 2 bytes, parece que tienes esta en la bolsa. Por cierto, no sé si lo has ejecutado con N = 32767 , pero la salida real es Fatal error: maximum recursion depth exceeded while calling a Python object.
Dennis
@ Dennis Sí, me encontré con eso en realidad, comienza bastante temprano, alrededor de 600 si no antes. La razón es que las expresiones se evalúan evaluando recursivamente todas las subexpresiones primero, por lo que x+x+...+xgenera una profundidad de recursión O (N). Quizás eso invalida esta respuesta. Agregaré una nota.
DLosc
El límite de recursión es fácilmente ajustable en Python, ¿no?
Dennis
@ Dennis Sí, aunque hay advertencias graves sobre lo que le hará a su sistema si lo configura demasiado alto, así que nunca lo he intentado. ;) Además, configurarlo no es posible desde Pip , por lo que me parece una trampa. Sin embargo, si quieres probarlo, me interesaría escuchar los resultados.
DLosc
He intentado. En mi máquina, aumentar el límite de recursión a 20000 ya es por defecto. Pero dado que la respuesta tiene que funcionar solo con suficiente memoria y potencia informática , eso no debería ser un problema.
Dennis
34

GolfScript, 10 bytes

!:{)::(}:!

Pruébelo en línea con Web Golfscript: N = 0 , N = 1 , N = 2 , N = 3 , N = 41

Web GolfScript tiene un límite de 1024 caracteres, pero el intérprete de Ruby maneja N = 32767 perfectamente:

$ curl -Ss http://www.golfscript.com/golfscript/golfscript.rb > golfscript.rb
$ echo '"!:{):"32768*":(}:!"32768*' | ruby golfscript.rb > mirror-level-32767.gs
$ ruby golfscript.rb mirror-level-32767.gs
32768

Cómo funciona

Sin ninguna entrada, GolfScript inicialmente tiene una cadena vacía en la pila.

En la primera mitad izquierda, sucede lo siguiente:

  • !aplica el NOT lógico a la cadena vacía. Esto empuja 1.

  • :{guarda el entero en la pila en la variable {.

    Sí, ese es un identificador válido, aunque no hay forma de recuperar el valor almacenado.

  • ) incrementa el número entero en la pila.

  • : Es una instrucción incompleta.

Las siguientes mitades izquierdas, sucede lo siguiente:

  • :!(donde :queda un sobrante de antes) guarda el número entero en la pila en la variable !.

    Sí, eso también es un identificador válido. Esto rompe el !comando, pero ya no lo usamos.

  • :{, )Y el :trabajo que antes.

En la primera mitad derecha, sucede lo siguiente:

  • ::(donde :queda un sobrante de antes) guarda el número entero en la pila en la variable :.

    Sí, incluso ese es un identificador válido. Al igual que con {, no hay forma de recuperar el valor almacenado.

  • ( disminuye el número entero en la pila, produciendo el número de mitades izquierdas.

  • }, ya que no tiene comparación y finaliza la ejecución de inmediato.

    Esta es una característica no documentada. Los llamo supercomentarios .

El código restante simplemente se ignora.

Dennis
fuente
Parece realmente extraño tener un incomparable }en la segunda mitad de su código en una competencia espejo.
ballesta25
Es un truco común en las variantes de palíndromo. En "\""/", la cuarta cita doble también sería inigualable ya que la segunda se ha escapado.
Dennis
27

Código máquina Z80, 8 6 bytes *

<8ww8> * Asume ciertas condiciones al ingresar desde Amstrad BASIC

<   INC A         // A=A+1
8w  JR C, #77     ## C is unset unless A has overflowed, does nothing

w   LD (HL), A    // Saves A to memory location in HL (randomly initialised)
8>  JR C, #3E     ## C is still unset, does nothing

Aes inicialmente 0 cuando se ingresa desde BASIC. ¡Incrementa A n veces, luego lo escribe n veces en la misma ubicación de memoria (que BASIC establece en una ubicación ligeramente aleatoria)! losJR operación Jump Relative nunca hace nada, ya que el Cindicador siempre está desactivado, por lo que se utiliza para "comentar" el siguiente byte. Esta versión es un poco engañosa al asumir ciertas condiciones de entrada, es decir, ingresar desde BASIC garantiza que Asiempre es 0. La ubicación de (HL)no está garantizada como segura, y de hecho, es probablemente una ubicación peligrosa. El siguiente código es mucho más robusto, por lo que es mucho más largo.

Código máquina Z80, 30 bytes

Como ASCII: o!.ww.!>A=o>{))((}<o=A<!.ww.!o

Básicamente, la primera mitad garantiza la creación de un valor cero y la segunda mitad lo incrementa y lo escribe en la memoria. En la versión ampliada a continuación, se ##indica un código que no sirve para nada en su mitad del espejo.

o   LD L, A       ## 
!.w LD HL, #772E  // Load specific address to not corrupt random memory!
w   LD (HL), A    ## Save random contents of A to memory
.!  LD L, #21     ## 
>A  LD A, #41     // A=#41
=   DEC A         // A=#40
o   LD L, A       // L=#40
>{  LD A, #7B     ## 
)   ADD HL, HL    // HL=#EE80
)   ADD HL, HL    // HL=#DD00. L=#00 at this point

((  JR Z, #28     ## 
}   LD A, L       // A=L
<   INC A         // A=L+1
o   LD L, A       // L=L+1
=   DEC A         // A=L
A   LD B, C       ## 
<   INC A         // A=L+1
!.w LD HL, #772E  // Load address back into HL
w   LD (HL), A    // Save contents of A to memory
.!  LD L, #21     ## 
o   LD L, A       // L=A

Desglose de las instrucciones permitidas:

n   op    description
--  ----  -----------
28  LD    LoaD 8-bit or 16-bit register
3   DEC   DECrement 8-bit or 16-bit register
1   INC   INCrement 8-bit or 16-bit register
1   ADD   ADD 8-bit or 16-bit register

Available but useless instructions:
3   JR    Jump Relative to signed 8-bit offset
1   DAA   Decimal Adjust Accumulator (treats the A register as two decimal digits
          instead of two hexadecimal digits and adjusts it if necessary)
1   CPL   1s ComPLement A
1   HALT  HALT the CPU until an interrupt is received

De las 39 instrucciones permitidas, 28 son operaciones de carga (el bloque de 0x40 a 0x7F son LDinstrucciones de un solo byte ), ¡la mayoría de las cuales no ayudan aquí! La única instrucción de carga en memoria aún permitida es lo LD (HL), Aque significa que tengo que almacenar el valor A. Dado que Aes el único registro que queda con un permitidoINC instrucción , ¡esto es realmente muy útil!

¡No puedo cargar Acon 0x00 para empezar porque ASCII 0x00 no es un personaje permitido! ¡Todos los valores disponibles están lejos de 0 y todas las instrucciones matemáticas y lógicas han sido rechazadas! Excepto ... que aún puedo hacer ADD HL, HL, ¡agregar 16 bits HLa sí mismo! Además de cargar directamente los valores (¡no se usa aquí!), INCrementing Ay DECrementing A, LoHL esta es la única forma que tengo de cambiar el valor de un registro! En realidad, hay una instrucción especializada que podría ser útil en la primera mitad, pero un trabajo difícil de resolver en la segunda mitad, y una instrucción complementaria que es casi inútil aquí y que solo ocuparía espacio.

Entonces, encontré el valor más cercano a 0 que pude: 0x41. ¿Cómo es eso cerca de 0? En binario es 0x01000001. ¡Así que lo decremento, lo cargo Ly lo hago ADD HL, HLdos veces! Lahora es cero, que vuelvo a cargar A! Desafortunadamente, el código ASCII ADD HL, HLes )así que ahora necesito usar (dos veces. Afortunadamente, (es JR Z, e, ¿dónde eestá el próximo byte? ¡Así que engulle el segundo byte y solo necesito asegurarme de que no haga nada teniendo cuidado con la Zbandera! La última instrucción para afectar el Zindicador fue DEC A(contra intuitivamente, ADD HL, HLno lo cambia) y como sé que Aera 0x40 en ese punto, está garantizado que Zno está configurado.

La primera instrucción en la segunda mitad. JR Z, #28 no hará nada las primeras 255 veces porque el indicador Z solo se puede establecer si A se ha desbordado de 255 a 0. Después de eso, la salida será incorrecta, ya que de todos modos solo está guardando valores de 8 bits que no debería importar El código no debe expandirse más de 255 veces.

El código debe ejecutarse como un fragmento, ya que se han rechazado todas las formas disponibles de regresar limpiamente. Todas las instrucciones de RETORNO están por encima de 0x80 y las pocas operaciones de salto permitidas solo pueden saltar a un desplazamiento positivo, ¡porque todos los valores negativos de 8 bits también se han rechazado!

CJ Dennis
fuente
66
QUÉ. QUE ES ESTO.
cloudfeet
44
Ahora he visto esta respuesta, usando GolfScript / J / etc. solo parece hacer trampa. : p
cloudfeet
¿Hay procesadores compatibles con Z80 con un registro A de 16 bits? Estoy preguntando ya que la pregunta requiere que el código tenga que funcionar para N = 32767 .
Dennis
1
@Dennis Para que un programa funcione para N = 32767 debe tener al menos 2 x 32767 o 65534 bytes de longitud. ¡El Z80 solo puede direccionar 65536 bytes de memoria, por lo que es una tarea imposible ya que no creo que pueda hacer que el programa sea más pequeño que 6 bytes! El Aregistro siempre es de 8 bits, de lo contrario el procesador no sería compatible con el Z80. ¡Diría que aquí se ha cubierto suficiente memoria y potencia informática !
CJ Dennis
1
@Dennis ¿Entiendes por qué ningún procesador compatible con Z80 tendrá un Aregistro que no sea de 8 bits? Cambiarlo a 16 bits rompería el código dependiendo de 255 + 1 = 0, por ejemplo. Tendría que inventar una CPU, llamémosla Z160, que usa un registro predeterminado de 16 bits pero aún usa el mismo conjunto de instrucciones de 8 bits del Z80. ¡Extraño!
CJ Dennis
19

J, 16 14 bytes

(_=_)]++[(_=_)

Usos:

   (_=_)]++[(_=_)
1
   (_=_)]+(_=_)]++[(_=_)+[(_=_)
2
   (_=_)]+(_=_)]+(_=_)]++[(_=_)+[(_=_)+[(_=_)
3

Explicación:

  • J evalúa de derecha a izquierda.

  • (_=_)es lo inf equals infque es cierto, tiene un valor de 1, por lo que la expresión se convierte 1+]...[+1. ( (8=8)También funcionaría, pero esto se ve más genial. :))

  • [y ]devolver sus argumentos izquierdo y derecho respectivamente si tienen 2 argumentos. Si obtienen solo 1, devuelven eso.

  • +agrega los 2 argumentos. Si solo obtiene 1, devuelve eso.

Ahora vamos a evaluar una expresión de nivel 3 (de derecha a izquierda):

(_=_)]+(_=_)]++[(_=_)+[(_=_)  NB. (_=_) is 1

1]+1]+1]++[1+[1+[1  NB. unary [, binary +

1]+1]+1]++[1+[2  NB. unary [, binary +

1]+1]+1]++[3  NB. unary [, unary +

1]+1]+1]+3  NB. unary +, binary ]

1]+1]+3  NB. unary +, binary ]

1]+3  NB. unary +, binary ]

3

Como vemos, la mitad derecha de la 1's se agrega y el lado izquierdo de la 1' s se omite, lo que resulta en el entero deseadoN , el nivel del espejo.

Pruébelo en línea aquí.

randomra
fuente
12

Haskell, 42 bytes

(8-8)-(-(8-8)^(8-8))--((8-8)^(8-8)-)-(8-8)

Afortunadamente, un comentario de línea en Haskell (-> --) se puede reflejar y la mitad (-> -) es una función válida. El resto son algunas matemáticas para obtener los números 0y 1. Básicamente tenemos (0)-(-1)un comentario N=0y un antecedente (0)-(-1)-en cada paso.

Si se permiten números de coma flotante para la salida, podemos construir 1desde 8/826 bytes:

Haskell, 26 bytes

(8-8)-(-8/8)--(8\8-)-(8-8)

Salidas 1.0, 2.0etc.

nimi
fuente
2
Esto es técnicamente inválido ya que debe ser un programa completo.
Calvin's Hobbies
@ Calvin'sHobbies: Ya veo. ¿Tenemos consenso sobre los requisitos mínimos para un programa completo? He buscado meta, pero solo encontré una discusión sobre funciones, no programas. Dependiendo de la definición de un programa completo, podría solucionar mi solución.
nimi
Lo llamaría un programa completo si puede guardarlo en un archivo program.hsy luego ejecutarlo $ runhaskell program.hsdesde la línea de comandos y ver el resultado. No conozco a Haskell, así que no puedo decir exactamente qué necesita cambiar.
Calvin's Hobbies
2
@ Calvin'sHobbies: runhaskelles un script de shell que configura un entorno y finalmente llama ghcal compilador Haskell. Puede ejecutar el código directamente con ghc: ghc -e "(8-8)-(-8/8)--(8\8-)-(8-8)". Esto se inicia ghcy evalúa el código proporcionado como argumento, imprime el resultado y sale. Sin REPL, sin interacción. Por supuesto, esto agregaría +1 al recuento de bytes para -e.
nimi
@nimi: -eno contribuye a la puntuación en este caso. No contamos bytes para perl -Eo gcc -std=c99tampoco.
Dennis
11

CJam, 14 bytes

]X+:+OooO+:+X[

Pruébelo en línea en el intérprete de CJam: N = 0 , N = 1 , N = 2 , N = 3 , N = 41

Tenga en cuenta que este código termina con un mensaje de error. Usando el intérprete de Java, ese mensaje de error puede suprimirse cerrando o redirigiendo STDERR. 1

Cómo funciona

En las mitades de la izquierda, sucede lo siguiente:

  • ] envuelve toda la pila en una matriz.

  • Xse une 1a esa matriz.

  • :+ calcula la suma de todos los elementos de la matriz.

  • Oo imprime el contenido de una matriz vacía (es decir, nada).

En la primera mitad derecha, sucede lo siguiente:

  • o imprime el entero en la pila, que es el resultado deseado.

  • O+ intenta agregar una matriz vacía al elemento superior de la pila.

    Sin embargo, la pila estaba vacía antes de empujar O. Esto falla y finaliza la ejecución del programa.

El código restante simplemente se ignora.

1 De acuerdo con la meta encuesta ¿Se debe permitir que las presentaciones salgan con un error? , esto está permitido.

Dennis
fuente
Sería escéptico sobre aceptar esto debido al error, pero como no está ganando, no estoy demasiado preocupado.
Calvin's Hobbies
Tareas como esta son sorprendentemente difíciles en CJam, considerando que es un lenguaje de golf. Incluso un error de sintaxis (por ejemplo, un operador indefinido) en un bloque no ejecutado impedirá que se ejecute todo el programa. Todavía estoy tratando de deshacerme del error.
Dennis