El hilo del desafío de los ladrones está aquí .
El desafío de los policías: diseñar un lenguaje de programación que parezca inutilizable para la programación, pero que admite la computación (o al menos la finalización de la tarea) a través de algún mecanismo no obvio.
Debe diseñar un lenguaje de programación simple que lea el código de un archivo de entrada y luego haga ... algo. Debe preparar un programa de solución que encuentre el tercer número más grande en la entrada cuando se ejecuta en su intérprete. Debe hacer que sea lo más difícil posible para los ladrones encontrar un programa de solución. Tenga en cuenta que los ladrones pueden publicar cualquier solución que realice la tarea, no solo la que tenía en mente.
Este es un concurso de popularidad. El objetivo de la policía es obtener la mayor cantidad de votos posible mientras sobrevive 8 días después de publicar el intérprete sin ser agrietado. Para este fin, las siguientes prácticas deberían ayudar:
- Explicando con precisión la semántica de tu idioma
- Escribir código legible
Se desaconsejan las siguientes tácticas:
- Usar cifrado, hash u otros métodos criptográficos. Si ve un lenguaje que emplea encriptación RSA, o se niega a ejecutar un programa a menos que su hash SHA-3 sea igual a 0x1936206392306, no dude en votar a favor.
Desafío de los ladrones: escriba un programa que encuentre el tercer entero más grande en la entrada cuando se ejecuta en el intérprete de la policía.
Este es relativamente sencillo. Para descifrar la respuesta de un policía, debe crear un programa que complete la tarea cuando se ejecute en su intérprete. Cuando descifre una respuesta, publique un comentario que diga "Agrietado" en la respuesta del policía que se vincula a su publicación. Quien descifra la mayor cantidad de policías gana el hilo de los ladrones.
Reglas de E / S
- Los intérpretes deben tomar un nombre de archivo en la línea de comando para el programa y utilizar entradas y salidas estándar cuando lo ejecutan.
- La entrada se dará en unario y constará solo de los caracteres
0
y1
(48 y 49 en ASCII). Un número N se codifica como N1s
seguido de a0
. Hay un adicional0
antes del final del archivo. Ejemplo: para la secuencia (3, 3, 1, 14), la entrada es11101110101111111111111100
. - Se garantiza que la entrada tenga al menos 3 números. Todos los números son enteros positivos.
- La salida será juzgada por el número de
1
correos impresos antes de que el programa se detenga. Otros personajes son ignorados.
En los siguientes ejemplos, la primera línea es la entrada en formato decimal; el segundo es la entrada real del programa; el tercero es una salida de muestra.
1, 1, 3
101011100
1
15, 18, 7, 2, 15, 12, 3, 1, 7, 17, 2, 13, 6, 8, 17, 7, 15, 11, 17, 2
111111111111111011111111111111111101111111011011111111111111101111111111110111010111111101111111111111111101101111111111111011111101111111101111111111111111101111111011111111111111101111111111101111111111111111101100
111111,ir23j11111111111u
247, 367, 863, 773, 808, 614, 2
<omitted>
<contains 773 1's>
Reglas aburridas para respuestas de policías:
- Para evitar la seguridad a través de la oscuridad, el intérprete debe estar escrito en un idioma en el top 100 de este índice TIOBE y tener un compilador / intérprete disponible gratuitamente.
- El intérprete no debe interpretar un idioma que se publicó antes de este desafío.
- El intérprete debe caber en su publicación y no estar alojado externamente.
- El intérprete debe ser determinista.
- El intérprete debe ser portátil y seguir el estándar de su propio idioma; no use comportamientos o errores indefinidos
- Si el programa de solución es demasiado largo para caber en la respuesta, debe publicar un programa que lo genere.
- El programa de solución debe consistir solo en ASCII imprimible y líneas nuevas.
- Debe ejecutar su programa de solución en menos de 1 hora en su propia computadora para cada una de las entradas de ejemplo anteriores.
- El programa debería funcionar para todos los enteros menores de 10 6 y cualquier número de enteros menores de 10 6 (no necesariamente en menos de una hora), siempre que la longitud de entrada total sea menor de 10 9 .
- Para estar seguro, un policía debe editar el programa de solución en la respuesta después de que hayan pasado 8 días.
Puntuación
El policía que se vuelve seguro con el puntaje más alto y un puntaje positivo, gana esta pregunta.
Respuestas:
Changeling (seguro)
ShapeScript
ShapeScript es un lenguaje de programación natural. Los desplazadores de forma (o Changelings , como prefieren ser llamados) pueden transformarse en un conjunto de instrucciones que les permite procesar datos.
ShapeScript es un lenguaje basado en pila con una sintaxis relativamente simple. Como era de esperar, la mayoría de sus incorporados tratan de alterar la forma de las cuerdas. Se interpreta, carácter por carácter, de la siguiente manera:
'
y"
comienza una cadena literal.Hasta que se encuentre la cita coincidente en el código fuente, todos los caracteres entre estas citas coincidentes se recopilan en una cadena, que luego se inserta en la pila.
0
para9
empujar los enteros 0 a 9 en la pila. Tenga en cuenta que10
empuja dos enteros.!
saca una cadena de la pila e intenta evaluarla como ShapeScript.?
saca un número entero de la pila y empuja una copia del elemento de la pila en ese índice.El índice 0 corresponde al elemento de la pila superior (LIFO) y el índice -1 al inferior.
_
saca un iterable de la pila y empuja su longitud.@
saca dos elementos de la pila y los empuja en orden inverso.$
saca dos cadenas de la pila y divide la más inferior en las instancias de la más alta. La lista resultante se empuja a cambio.&
saca una cadena (la más alta) y un iterable de la pila, y se une al iterable, usando la cadena como separador. La cadena resultante se empuja a cambio.Si se usa ShapeScript en nuestro planeta, dado que las pitones son los parientes más cercanos de los Changelings en la Tierra, todos los demás caracteres c muestran dos elementos x e y (los más altos) de la pila e intentan evaluar el código de Python
x c y
.Por ejemplo, la secuencia de caracteres
23+
se evaluaría2+3
, mientras que la secuencia de caracteres"one"3*
se evaluaría'one'*3
y la secuencia de caracteres1''A
se evaluaría1A''
.En el último caso, dado que el resultado no es Python válido, el Changeling se quejaría de que su forma actual no está propuesta (error de sintaxis), ya que no es ShapeScript válido.
Antes de ejecutar el código, el intérprete colocará toda la entrada del usuario en forma de una cadena en la pila. Después de ejecutar el código fuente, el intérprete imprimirá todos los elementos en la pila. Si falla alguna parte en el medio, el Changeling se quejará de que su forma actual es inadecuada (error de tiempo de ejecución).
Cambio de forma
En su estado natural, los Changelings no toman la forma de ShapeScript. Sin embargo, algunos de ellos pueden transformarse en un código fuente potencial (que no es necesariamente útil o incluso sintácticamente válido).
Todos los Changelings elegibles tienen la siguiente forma natural:
Todas las líneas deben tener el mismo número de caracteres.
Todas las líneas deben consistir en caracteres ASCII imprimibles, seguidos de un solo salto de línea.
El número de líneas debe coincidir con el número de caracteres imprimibles por línea.
Por ejemplo, la secuencia de bytes
ab\ncd\n
es un Changeling elegible.En su intento de cambiar a ShapeScript, Changeling sufre la siguiente transformación:
Inicialmente, no hay código fuente.
Para cada línea sucede lo siguiente:
El acumulador de Changeling se establece en cero.
Para cada carácter c de la línea (incluido el avance de línea final), el punto de código de c se XOR con el acumulador dividido por 2, y el carácter Unicode que corresponde al punto de código resultante se agrega al código fuente.
Después, la diferencia entre el punto de código de c y el punto de código de un espacio (32) se agrega al acumulador.
Si alguna parte de lo anterior falla, el Changeling se quejará de que su forma actual es desagradable.
Después de que se hayan procesado todas las líneas, la transformación de Changeling en ShapeScript (con suerte válida) se completa y se ejecuta el código resultante.
Solución (ShapeScript)
ShapeScript en realidad resultó ser bastante utilizable; incluso puede realizar pruebas de primalidad ( prueba ) y, por lo tanto, satisface nuestra definición de lenguaje de programación.
He reeditado ShapeScript en GitHub , con una sintaxis ligeramente modificada y una mejor E / S.
El código hace lo siguiente:
Solución (Changeling)
Al igual que todos los programas Changeling, este código tiene un salto de línea final.
ShapeScript producirá un error de inmediato en cualquier carácter que no se entienda, pero podemos insertar cadenas arbitrarias como rellenos y reventarlas más tarde. Esto nos permite poner solo una pequeña cantidad de código en cada línea (al principio, donde el acumulador es pequeño), seguido de una apertura
"
. Si comenzamos la siguiente línea con"#
, cerramos y sacamos la cadena sin afectar el código real.Además, tenemos que superar tres obstáculos menores:
La cadena larga en el código ShapeScript es un token único, y no podremos ajustarlo en una línea.
Vamos a empujar esta cadena en trozos (
'@'
,'1?'
, etc.), lo que vamos a concatenar más tarde.El punto de código de
_
es bastante alto, y empujar'_'
será problemático.Sin embargo, podremos presionar
'_@'
sin esfuerzo, seguido de otro'@'
para deshacer el intercambio.El código ShapeScript que nuestro Changeling generará se ve así 1 :
Encontré el código Changeling ejecutando el código ShapeScript anterior a través de este convertidor . 2
Intérprete (Python 3)
1 Cada línea se rellena con basura aleatoria a la cantidad de líneas, y los avances de línea no están realmente presentes.
2 Los números en la parte inferior indican el punto de código más bajo y más alto en el código Changeling, que debe permanecer entre 32 y 126.
fuente
0"#002?'+'&'0'$'0?2?-@2?>*+00'&!++'1'*'0'+@1?$0?''&@_2-2?*@+@"3*!@#
. Sin embargo, he renunciado a encontrar un Changeling para ello. Incluso intercaladas con las declaraciones en su mayoría inútiles, no he sido capaz de conseguir más de 20 bytes en.Shuffle (escrito en C ++), ¡Agrietado! por Martin
Editar Martin lo descifró. Para ver su solución, haga clic en el enlace. Mi solución también ha sido añadida.
Editar Comando fijo
print-d
para poder manejar tanto registros como pilas. Como este es un comando de depuración que no está permitido en una solución, no debería afectar a nadie que use la versión anterior del intérpreteTodavía soy nuevo en esto, así que si hay algún problema con mi respuesta o mi intérprete, hágamelo saber. Solicite aclaraciones si algo no está claro.
No me imagino que esto sea demasiado difícil, pero espero que proporcione algún tipo de desafío. Lo que hace que la reproducción aleatoria sea bastante inutilizable es que solo se imprimirá cuando las cosas estén en su lugar correcto.
-> Conceptos básicos:
Hay 24 pilas, las llamamos
stack1, ... stack24
. Estas pilas viven en una lista. Al comienzo de cualquier programa, estas pilas tienen cero empujado y comienzan en su lugar correcto, es decir, se apilan i en la posición i-ésima de la lista (tenga en cuenta que indexaremos comenzando desde 1, a diferencia de C ++). Durante el curso de un programa, el orden de las pilas dentro de la lista cambiará. Esto es importante por razones que se explicarán cuando discuta los comandos.Hay 5 registros disponibles para su uso. Se llaman
Alberto
,Gertrude
,Hans
,Leopold
,ShabbySam
. Cada uno de estos se establece en cero al comienzo de un programa.Entonces, al comienzo de cualquier programa, hay 24 pilas, cada una con su número que coincide con su índice en la lista de la pila. Cada pila tiene exactamente un cero en la parte superior. Cada uno de los cinco registros se inicializa a cero.
-> Comandos y sintaxis :
Hay 13 comandos (comando de depuración +1) que están disponibles en Shuffle. Son los siguientes
cinpush
Este comando no toma argumentos. Espera la entrada de la línea de comandos de la manera descrita en la pregunta (otra entrada conducirá a resultados no especificados / indefinidos). Luego divide la cadena de entrada en enteros, por ejemplo,101011100
->1,1,3
. Para cada entrada recibida, hace lo siguiente: (1) permuta la lista de pilas en función del valor. Deje que el valor entero en cuestión se llame a . Si a es menor que 10, hace permutación u . Si a está entre 9 y 30 (no incluido), hace permutación d . De lo contrario, hace permutación r . (2) Luego empuja unen la pila que está primero en la lista. Tenga en cuenta que no me refierostack1
(aunque puede ser el caso questack1
es el primero en la lista). Las permutaciones se definen a continuación. Dado quecinpush
es la única forma de obtener información del usuario , debe aparecer en cualquier solución.mov value register
Elmov
comando es básicamente una asignación variable. Asignavalue
aregister
.value
puede tomar varias formas: puede ser (1) un número entero, por ejemplo47
(2) el nombre de un registro diferente, por ejemploHans
(3) el índice de una pila seguido de 's', por ejemplo4s
. Tenga en cuenta que este es el índice en la lista, no el número de la pila. Como tal, el número no debe exceder 24.Algunos
mov
ejemplos:movfs index register
Esto significa 'moverse de la pila'. Es similar almov
comando. Existe para que pueda acceder a una pila indexada por un registro. Por ejemplo, si anteriormente configuró Hans igual a 4 (mov 4 Hans
) Entonces puede utilizarmovfs Hans Gertrude
para establecer Gertrude igual a la parte superior de la pila 4. Este tipo de comportamiento no es accesible simplemente usandomov
.inc register
aumenta el valor del registro en 1.dec register
disminuye el valor del registro en 1.compg value value register
Esto significa 'comparar más grande'. Establece el registro igual al mayor de los dos valores.value
puede ser un número entero, un registro o un índice de pila seguido de 's', como se indicó anteriormente.compl value value register
'comparar menor' igual que el anterior, excepto que toma el valor más pequeño.gte value1 value2 register
Comprueba sivalue1 >= value2
luego pone el valor booleano (como 1 o 0) enregister
.POP!! index
aparece en la parte superior de la pila indexadaindex
en la lista de la pila.jmp label
salta incondicionalmente a la etiquetalabel
. Este es un buen momento para hablar sobre etiquetas. Una etiqueta es una palabra seguida de ':'. El intérprete analiza previamente las etiquetas, por lo que puede saltar a las etiquetas y retroceder.jz value label
salta alabel
sivalue
es cero.jnz value label
salta alabel
sivalue
no es cero.Ejemplos de etiquetas y saltos:
"shuffle" permutation
Aquí está el comando shuffle. Esto le permite permutar la lista de pilas. Hay tres permutaciones válidos que se pueden utilizar como argumentos,l
,f
, yb
.print register
Esto verifica si todas las pilas están en sus posiciones iniciales, es decir, la pila i está en el índice i en la lista de la pila. Si este es el caso, imprime el valor enregister
en unario. De lo contrario, imprime un error desagradable. Como puede ver, para generar cualquier cosa, todas las pilas deben estar en los lugares correctos.done!
esto le dice al programa que salga sin error. Si el programa finaliza sindone!
, imprimirá en la consola el número en la parte superior de cada pila seguido del número de la pila. El orden en que se imprimen las pilas es el orden en que aparecen en la lista de pilas. Si una pila está vacía, se omitirá. Este comportamiento tiene fines de depuración y no se puede usar en una solución.print-d value
esto imprime el valor de la pila, el registro o el entero dado (para acceder a la pila i , pasaris
como argumento, como se explicó anteriormente). Esta es una herramienta de depuración y no forma parte del lenguaje, por lo que no está permitida en una solución.-> Aquí está el código del intérprete
Todo el análisis ocurre en la función principal. Aquí es donde lo encontrará analizando comandos específicos.
-> Permutaciones Las permutaciones permutan los elementos de la lista de la pila de la siguiente manera:
Donde significa que
(Estos también aparecen en el código del intérprete. Si hay una discrepancia, el intérprete es correcto).
-> Ejemplo simple
Estos dos programas simples imprimen los números del 24 al 1 (en unario) sin espacios en blanco.
o
Son el mismo programa.
Explicación y solución:
Martin también tiene una buena explicación en su respuesta .
Como Martin descubrió, este lenguaje se inspiró en el cubo de bolsillo (también conocido como cubo de Rubik 2x2). Las 24 pilas son como los 24 cuadrados individuales en el cubo. Las permutaciones son los movimientos básicos permitidos: arriba, abajo, derecha, izquierda, adelante, atrás.
La lucha principal aquí es que cuando se empujan los valores, solo se usan tres movimientos: arriba, abajo y derecha. Sin embargo, no tienes acceso a estos movimientos cuando "barajas" las pilas. Solo tienes los otros tres movimientos.
Como resultado, ambos conjuntos de tres movimientos en realidad abarcan todo el grupo (es decir, son generadores), por lo que el problema es solucionable. Esto significa que en realidad puedes resolver cualquier cubo de Rubik 2x2 solo usando 3 de los movimientos.
Todo lo que queda por hacer es descubrir cómo deshacer los movimientos hacia arriba, hacia abajo y hacia la derecha usando los otros tres. Con este fin, empleé un sistema de álgebra computacional llamado GAP .
Después de deshacer las permutaciones, encontrar el tercer número más grande es bastante trivial.
fuente
Brian y Chuck , agrietados por caja de cartón
Hace un tiempo que me intriga la idea de un lenguaje de programación en el que dos programas interactúan entre sí (probablemente inspirados por ROCB ). Este desafío fue un buen incentivo para abordar este concepto por fin al intentar mantener el lenguaje lo más mínimo posible. Los objetivos de diseño eran hacer que el lenguaje fuera completo de Turing, mientras que cada una de sus partes individualmente no es completo para Turing. Además, incluso los dos juntos no deberían estar completos de Turing sin hacer uso de la manipulación del código fuente. Creo que he tenido éxito con eso, pero aún no he probado ninguna de esas cosas formalmente. Entonces, sin más preámbulos, te presento ...
Los protagonistas
Brian y Chuck son dos programas similares a Brainfuck. Solo uno de ellos se está ejecutando en un momento dado, comenzando con Brian. El problema es que la cinta de memoria de Brian también es el código fuente de Chuck. Y la cinta de memoria de Chuck también es el código fuente de Brian. Además, el cabezal de cinta de Brian también es el puntero de instrucciones de Chuck y viceversa. Las cintas son semi-infinitas (es decir, infinitas a la derecha) y pueden contener enteros de precisión arbitraria firmados, inicializados a cero (a menos que el código fuente especifique lo contrario).
Dado que el código fuente también es una cinta de memoria, los comandos se definen técnicamente por valores enteros, pero corresponden a caracteres razonables. Existen los siguientes comandos:
,
(44
): Lee un byte de STDIN en la celda de memoria actual. Solo Brian puede hacer esto. Este comando es un no-op para Chuck..
(46
): Escribe la celda de memoria actual, módulo 256, como un byte a STDOUT. Solo Chuck puede hacer esto. Este comando es un no-op para Brian.+
(43
): Incrementa la celda de memoria actual.-
(45
): Disminuye la celda de memoria actual.?
(63
): Si la celda de memoria actual es cero, esto es un no-op. De lo contrario, transfiera el control al otro programa. El cabezal de la cinta en el programa que utiliza?
permanecerá en el?
. El cabezal de la cinta del otro programa moverá una celda a la derecha antes de ejecutar el primer comando (por lo que la celda que se utiliza como prueba no se ejecuta).<
(60
): Mueva el cabezal de la cinta una celda hacia la izquierda. Esto es un no-op si el cabezal de la cinta ya está en el extremo izquierdo de la cinta.>
(62
): Mueva el cabezal de la cinta una celda hacia la derecha.{
(123
): Mueva repetidamente el cabezal de la cinta hacia la izquierda hasta que la celda actual sea cero o se llegue al extremo izquierdo de la cinta.}
(125
): Mueva repetidamente el cabezal de la cinta hacia la derecha hasta que la celda actual sea cero.El programa termina cuando el puntero de instrucciones del programa activo alcanza un punto donde no hay más instrucciones a su derecha.
El código fuente
El archivo fuente se procesa de la siguiente manera:
```
, el archivo se dividirá en dos partes alrededor de la primera aparición de esa cadena. Todos los espacios en blanco iniciales y finales se eliminan y la primera parte se usa como código fuente para Brian y la segunda parte para Chuck._
en ambos programas se reemplazan con bytes NULL.Como ejemplo, el siguiente archivo fuente
Produciría las siguientes cintas iniciales:
El interprete
El intérprete está escrito en rubí. Se necesitan dos marcas de línea de comandos que no deben ser utilizadas por ninguna solución (ya que no forman parte de la especificación del lenguaje real):
-d
: Con esta bandera, Brian y Chuck entienden dos comandos más.!
imprimirá una representación de cadena de ambas cintas de memoria, el programa activo se enumerará primero (a^
marcará los cabezales de cinta actuales).@
también lo hará, pero luego terminará inmediatamente el programa. Como soy vago, ninguno de esos funciona si son el último comando del programa, así que si quieres usarlos allí, repítelos o escribe un no-op después de ellos.-D
: Este es el modo de depuración detallado. Imprimirá la misma información de depuración que!
después de cada tic.@
También funciona en este modo.Aquí está el código:
Aquí está mi propia solución (manuscrita) al problema:
Este código es ejecutable tal cual, porque todas las anotaciones usan no-ops y son omitidas por
{
y}
.La idea básica es:
1
s, incremente ese elemento.Cuando estamos leyendo un
0
, haz una limpieza. Si el entero resultante fue mayor que cero, regrese a 1.Ahora tenemos una lista de los números de entrada al final de la cinta de Chuck y sabemos la longitud de la lista.
Reste 2 de la longitud de la lista (por lo que los siguientes pasos ignoran los dos elementos más grandes), llame a esto
N
.Mientras tanto
N > 0
, incremente un total acumulado y luego disminuya todos los elementos de la lista. Siempre que un elemento de la lista llegue a cero, disminuyaN
.Al final de esto, el total acumulado contendrá el tercer mayor número en la entrada,
M
.Escriba
M
copias.
al final de la cinta de Chuck.1
en la cinta de Brian y luego ejecute los generados.
al final.Después de terminar esto, me di cuenta de que podía simplificarlo bastante en algunos lugares. Por ejemplo, en lugar de hacer un seguimiento de ese contador y escribirlos
.
en la cinta de Chuck, podría imprimir uno de1
inmediato, cada vez antes de disminuir todos los elementos de la lista. Sin embargo, hacer cambios a este código es bastante difícil, ya que propaga otros cambios por todo el lugar, por lo que no me molesté en hacer el cambio.Lo interesante es cómo hacer un seguimiento de la lista y cómo recorrerla. No puede simplemente almacenar los números consecutivamente en la cinta de Chuck, porque si desea verificar una condición en uno de los elementos de la lista, corre el riesgo de ejecutar el resto de la lista que puede contener un código válido. Tampoco sabe cuánto tiempo durará la lista, por lo que no puede reservar un espacio frente al código de Chuck.
El siguiente problema es que debemos dejar que la lista disminuya
N
mientras la procesamos, y necesitamos volver al mismo lugar que antes. Pero{
y}
simplemente pasaría por alto la lista completa.Entonces, necesitamos escribir algo de código dinámicamente en Chuck. De hecho, cada elemento de la lista
i
tiene la forma:1
es un marcador que podemos establecer en cero para indicar dónde dejamos de procesar la lista. Su propósito es atrapar{
o}
que simplemente pasará sobre el código y eli
. También usamos este valor para verificar si estamos al final de la lista durante el procesamiento, por lo tanto, mientras no lo estemos, esto será1
y el condicional?
cambiará el control a Chuck.Code A
se utiliza para manejar esa situación y mover la IP en Brian en consecuencia.Ahora, cuando disminuimos
i
, necesitamos verificar sii
ya es cero. Si bien no es así,?
cambiará de nuevo el control, por lo queCode B
está ahí para manejar eso.fuente
HPR, escrito en Python 3 ( descifrado por TheNumberOne )
HPR (el nombre no significa nada) es un lenguaje para procesar listas de enteros. Está diseñado para ser minimalista , extremadamente limitado y libre de restricciones "artificiales" . La programación en HPR es dolorosa, no porque tenga que resolver un rompecabezas para evitar que el intérprete le grite, sino porque es difícil hacer que un programa haga algo útil. No sé si HPR es capaz de hacer algo sustancialmente más interesante que calcular el tercer elemento más grande de una lista.
Especificación de idioma
Un programa HPR se ejecuta en un entorno , que es un conjunto sin orden de duplicados de enteros no negativos y listas de enteros no negativos. Inicialmente, el entorno contiene solo la lista de entrada (el intérprete lo analiza por usted). Hay tres comandos y dos operadores de "flujo de control" que modifican el entorno:
*
elimina el primer elemento de cada lista no vacía en el entorno y lo coloca en el entorno. Las listas vacías no se ven afectadas. Por ejemplo, se transforma-
disminuye todos los números en el entorno y luego elimina elementos negativos. Por ejemplo, se transforma$
Rota cada lista del entorno un paso hacia la izquierda. Por ejemplo, se transforma!(A)(B)
, dondeA
yB
son programas, es básicamente unwhile
bucle. Realiza la "acción"A
hasta que la "prueba"B
dé como resultado un entorno vacío. Esto puede producir un bucle infinito.#(A)(B)
, dondeA
yB
son programas, aplicaA
yB
al entorno actual y toma la diferencia simétrica de los resultados.Los comandos se ejecutan de izquierda a derecha. Al final, el tamaño del entorno se imprime en unario.
El interprete
Este intérprete presenta el comando de depuración
?
, que imprime el entorno sin modificarlo. No debería aparecer en ninguna solución a la tarea. Todos los caracteres excepto*-$!#()?
se ignoran simplemente, por lo que puede escribir comentarios directamente en el código. Finalmente, el intérprete reconoce el modismo!(A)(#(A)())
como "actuarA
hasta que el resultado ya no cambie", y lo optimiza para una velocidad adicional (lo necesitaba para que mi solución terminara en menos de una hora en el último caso de prueba).Mi solución
Mi solución de referencia tiene 484 bytes de longitud, muy corta en comparación con el programa de 3271 bytes de TheNumberOne. Esto es muy probable debido al sofisticado y sorprendente sistema macro que TheNumberOne desarrolló para programar en HPR. La idea principal en nuestros dos programas es similar:
Sin embargo, por lo que puedo decir, los detalles exactos de implementación son bastante diferentes. Aquí está mi solución:
Y aquí está el programa comentado de Python que lo produce (nada lujoso aquí, solo manipulación básica de cadenas para deshacerse de toda la repetición):
fuente
TKDYNS (Para matar al dragón, necesitas una espada) - Cracked por Martin Büttner
EDITAR: He agregado mi solución y explicación debajo de la publicación principal.
Antecedentes
En este lenguaje, tomas el control de un valiente guerrero al que se le ha encomendado la tarea de matar a un terrible dragón. El dragón vive en un laberinto subterráneo, lleno de peligros y peligros, y hasta ahora, nadie ha sido capaz de mapearlo y sobrevivir. Esto significa que debes navegar hacia el dragón en la oscuridad total, con nada más que intuición y valentía para guiarte.
...
Bueno, no del todo. Has traído un suministro casi ilimitado de secuaces desechables contigo, y están dispuestos a ir por delante de ti para descubrir la ruta segura. Desafortunadamente, todos son tan gruesos como dos tablones cortos, y solo harán exactamente lo que les dices. Depende de usted encontrar un método inteligente para garantizar que sus secuaces descubran el camino correcto.
Algunos mas detalles
La guarida del dragón toma la forma de una cuadrícula de 10x10. Entre ciertos puntos adyacentes en la cuadrícula, hay una pasarela estrecha; entre otros, hay un profundo abismo y una muerte segura. Un diseño de ejemplo para una cuadrícula de 4x4 podría ser el siguiente:
Usted sabe que siempre hay una manera de llegar de un punto a otro, pero no más de lo que se le ha revelado.
Para derrotar con éxito al dragón, primero debes recolectar algunos elementos que podrás combinar para crear una cuchilla mágica que mata dragones. Convenientemente, todas las piezas de esta arma se han dispersado por la guarida del dragón. Simplemente tienes que recogerlos.
El giro es que cada pieza del arma ha quedado atrapada. Cada vez que se recolecta uno, cambia el diseño de las pasarelas. Los caminos previamente seguros ahora pueden conducir a una muerte segura, y viceversa.
Comandos
Solo hay 5 comandos válidos.
<
- Da un paso a la izquierda>
- Da un paso a la derecha^
- Da un paso hacia arribav
- Da un paso hacia abajoc
- Recoge cualquier artículo que esté por ahí en tu posición actual. Si había elementos presentes, el diseño de la guarida cambia. Con las posiciones numeradas en filas como arriba, tome su posición módulo 10. Hay 10 diseños codificados en el intérprete, y el diseño cambia al correspondiente. Por ejemplo, si está en la posición 13, el diseño cambia alayouts[3]
Los diseños tal como aparecen en el intérprete se han codificado en enteros de la siguiente manera:
El diseño vacío se codifica a cero.
Para cada borde en el diseño, deje que
x
sea la menor de las dos posiciones a las que se une.Si el paso es horizontal, agréguelo
2^(2*x)
a la codificación (eso es potencia, no XOR)Si el paso es vertical, agréguelo
2^(2*x + 1)
a la codificación.Flujo de ejecución
El intérprete se ejecuta con el nombre de un archivo fuente como argumento de línea de comandos.
Cuando se ejecuta el intérprete, solicitará al usuario que proporcione una búsqueda. Esta entrada debe estar en la forma descrita en la pregunta, y determina las ubicaciones en la guarida de los componentes del arma. Específicamente, cada entero de entrada se toma el módulo 100 y se coloca en la ubicación correspondiente en la guarida.
Cada programa fuente consta de varias líneas, cada línea que consiste en una secuencia de los 5 caracteres válidos anteriores. Estas líneas representan tus secuaces. Usted, el guerrero, realiza un seguimiento de una secuencia de acciones que se sabe que son seguras. Inicialmente, no sabes nada sobre la guarida, por lo que esta secuencia está vacía. Tomando cada minion por turno, se realiza lo siguiente, comenzando desde la posición 0:
El minion recibe instrucciones de realizar todas las acciones que se sabe que son seguras, seguidas de las acciones en su propia línea de código.
Si el súbdito muere en algún momento, se le notificará esto y la guarida se restablecerá a su configuración inicial. Todos los artículos se reemplazan y las pasarelas vuelven a sus posiciones iniciales.
Si, en cambio, el minion sobrevive, entonces lo vaporizas de todos modos, después de todo, es solo un minion. Como antes, esto activa el restablecimiento de la guarida a su estado inicial, pero esta vez, agrega las acciones de la línea de código del minion a la secuencia de acciones conocidas como seguras.
Una vez que todos los secuaces se han agotado, usted, el guerrero, realiza todas las acciones que se sabe que son seguras, nuevamente comenzando desde la posición 0. Hay dos resultados posibles:
Recoges todas las piezas del arma; en este caso, matas con éxito al dragón y se emite un emocionante mensaje de victoria. Este mensaje de victoria contendrá, entre otros caracteres,
n
unos, donden
es el tercer número más alto proporcionado como entrada.No has podido recoger algunas de las piezas del arma; en este caso, el dragón sigue vivo y has fallado en tu búsqueda.
Código de intérprete (Python 2)
Mucha suerte, valiente guerrero.
Mi solucion y explicacion
Aquí hay un script de Python que genera código fuente para resolver el problema. Por interés, el código fuente final de Martin es aproximadamente 5 veces más pequeño que el código producido por mi script. Por otro lado, mi script para generar el código es aproximadamente 15 veces más pequeño que el programa Mathematica de Martin ...
Estructura basica
Esto genera 990 líneas de código fuente, que vienen en grupos de 10. Las primeras 10 líneas contienen instrucciones que intentan mover a un súbdito de una posición
0
a otra1
, y luego recolectan un elemento, un conjunto para cada diseño posible. Las siguientes 10 líneas contienen instrucciones que intentan mover a un súbdito de una posición1
a otra2
y luego recoger un objeto. Y así sucesivamente ... Estos caminos se calculan con lapath
función en el guión - que sólo hace un simple búsqueda en profundidad.Si podemos asegurarnos de que, en cada grupo de 10, precisamente un minion tenga éxito, entonces habremos resuelto el problema.
El problema con el enfoque
Es posible que no siempre sea el caso de que precisamente un minion del grupo de 10 tenga éxito; por ejemplo, un minion diseñado para moverse de una posición
0
a otra1
podría accidentalmente tener éxito en moverse de una posición1
a otra2
(debido a las similitudes en los diseños), y que el error de cálculo se propagará, lo que podría causar fallas.Como arreglarlo
La solución que usé fue la siguiente:
Por cada súbdito que intente ir de una posición
n
a otran+1
, primero hágale caminar de una posiciónn
a otra0
(la esquina superior izquierda) y de regreso, luego de una posiciónn
a otra99
(la esquina inferior derecha) y de regreso. Estas instrucciones solo pueden llevarse a cabo de forma segura desden
cualquier posición : cualquier otra posición inicial y el súbdito se alejará del borde.Por lo tanto, estas instrucciones adicionales evitan que los súbditos vayan accidentalmente a un lugar al que no están destinados, y esto garantiza que exactamente un súbdito de cada grupo de 10 sea exitoso. Tenga en cuenta que no es necesariamente el súbdito que espera que sea; podría ser el caso de que el súbdito que cree que está en el diseño 0 tiene éxito, incluso cuando realmente estamos en el diseño 7, pero en cualquier caso, el hecho de que tenemos ahora cambiar de posición significa que todos los demás súbditos del grupo necesariamente morirán. La
assert_at
función calcula estos pasos adicionales y lasafe_path
función devuelve una ruta que es la concatenación de estos pasos adicionales con la ruta ordinaria.fuente
Firetype, agrietado por Martin Büttner
Una mezcla realmente extraña de BF y CJam. ¡Y quién sabe qué más! Estoy bastante seguro de que será fácil, pero de todos modos fue divertido. FYI, el nombre se refiere a Vermillion Fire de Final Fantasy Type-0 .
NOTA : Perdóneme por cualquier ambigüedad en esta descripción. No soy el mejor escritor ...: O
¡Martin resolvió esto muy rápido! Este fue mi programa original para resolver el problema:
Sintaxis
Un script Firetype es básicamente una lista de líneas. El primer carácter de cada línea es el comando a ejecutar. Las líneas vacías son básicamente NOP.
Semántica
Tiene una variedad de enteros y un puntero (piense BF). Puede mover elementos de izquierda a derecha o "empujar" en la matriz.
Emprendedor
Cuando "empujas" un elemento y estás al final de la matriz, se agregará un elemento adicional al final. Si no está al final, se anulará el siguiente elemento. En cualquier caso, el puntero siempre se incrementará.
Comandos
_
Empuje un cero en la matriz.
+
Incremente el elemento en el puntero actual.
-
Disminuya el elemento en el puntero actual.
*
Duplique el elemento en el puntero actual.
/
Reducir a la mitad el elemento en el puntero actual.
%
Tome el elemento en el puntero actual y salte varias líneas hacia adelante, y mueva el puntero hacia la izquierda. Si el valor es negativo, salta hacia atrás en su lugar.
=
Tome el elemento en el puntero actual y salte a esa línea + 1. Por ejemplo, si el elemento actual es
0
, saltará a la línea1
. Esto también mueve el puntero a la izquierda.,
Lea un carácter de la entrada estándar y presione su valor ASCII.
^
Tome el elemento en el puntero actual, inténtelo como el valor ASCII para un carácter y conviértalo en un entero. Por ejemplo, si el valor actual es
49
(el valor ASCII de1
), el elemento en el puntero actual se establecerá en el entero1
..
Escribe el número actual en la pantalla.
!
Tome el elemento en el puntero actual y repita la siguiente línea muchas veces. También mueve el puntero a la izquierda.
<
Mueve el puntero hacia la izquierda. Si ya está al principio, se produce un error.
>
Mueve el puntero hacia la derecha. Si ya está al final, se produce un error.
~
Si el elemento actual no es cero, reemplácelo con
0
; de lo contrario, reemplácelo con1
.|
Cuadrar el elemento actual.
@
Establecer el elemento actual a la longitud de la matriz.
`
Duplicar el elemento actual.
\
Ordenar los elementos en y antes del puntero.
#
Negar el elemento actual.
El interprete
También disponible en Github .
fuente
self.ptr-1
para acceder, probablemente debería marcarself.ptr>0
no>=0
. (Esto no debería invalidar ningún programa válido, pero podría hacer que algunos programas funcionen accidentalmente, lo cual no debería).=
establece el valor enarray() - 1
, la documentación dice+1
?Acc !! (seguro)
Está de vuelta ...
... y con
suertedefinitivamente más a prueba de lagunas.Ya leí el Acc! Especificaciones. ¿Cómo es Acc !! ¿diferente?
En Acc !! , las variables de bucle quedan fuera de alcance cuando el bucle sale. Solo puedes usarlos dentro del bucle. En el exterior, obtendrá un error "el nombre no está definido". Aparte de este cambio, los idiomas son idénticos.
Declaraciones
Los comandos se analizan línea por línea. Hay tres tipos de comando:
Count <var> while <cond>
Cuenta
<var>
desde 0 siempre que<cond>
no sea cero, equivalente a C ++for(int <var>=0; <cond>; <var>++)
. El contador de bucle puede ser cualquier letra minúscula. La condición puede ser cualquier expresión, que no implique necesariamente la variable de bucle. El ciclo se detiene cuando el valor de la condición se convierte en 0.Los bucles requieren llaves rizadas de estilo K y R (en particular, la variante Stroustrup ):
Como se mencionó anteriormente, las variables de bucle solo están disponibles dentro de sus bucles ; intentar hacer referencia a ellos luego causa un error.
Write <charcode>
Emite un solo carácter con el valor ASCII / Unicode dado a stdout. El código de char puede ser cualquier expresión.
Cualquier expresión en sí misma se evalúa y se asigna de nuevo al acumulador (al que se puede acceder como
_
). Por lo tanto, por ejemplo,3
es una declaración que establece el acumulador en 3;_ + 1
incrementa el acumulador; y_ * N
lee un personaje y multiplica el acumulador por su código de char.Nota: el acumulador es la única variable a la que se puede asignar directamente; variables de bucle y
N
se pueden usar en cálculos pero no se pueden modificar.El acumulador es inicialmente 0.
Expresiones
Una expresión puede incluir literales enteros, variables de bucle (
a-z
),_
para el acumulador y el valor especialN
, que lee un carácter y evalúa su código de caracteres cada vez que se usa. Nota: esto significa que solo tienes una oportunidad para leer cada personaje; la próxima vez que lo usesN
, leerás el siguiente.Los operadores son:
+
, además-
resta negación unaria*
multiplicación/
, División entera%
módulo^
exponenciaciónLos paréntesis pueden usarse para imponer la precedencia de las operaciones. Cualquier otro carácter en una expresión es un error de sintaxis.
Espacio en blanco y comentarios
Los espacios en blanco iniciales y finales y las líneas vacías se ignoran. El espacio en blanco en los encabezados del bucle debe ser exactamente como se muestra, con un solo espacio entre el encabezado del bucle y la llave de apertura. El espacio en blanco dentro de las expresiones es opcional.
#
comienza un comentario de una sola línea.De entrada y salida
Acc !! espera una sola línea de caracteres como entrada. Cada carácter de entrada se puede recuperar en secuencia y su código de char procesado usando
N
. Intentar leer más allá del último carácter de la línea provoca un error. Se puede generar un carácter pasando su código de char a laWrite
instrucción.Interprete
El intérprete (escrito en Python 3) traduce Acc !! codifique en Python y
exec
listo.Solución
La caída del Acc! Original Eran variables de bucle que seguían siendo accesibles fuera de sus bucles. Esto permitió guardar copias del acumulador, lo que hizo que la solución fuera demasiado fácil.
Aquí, sin este agujero de bucle (lo siento), solo tenemos el acumulador para almacenar cosas. Sin embargo, para resolver la tarea, necesitamos almacenar cuatro valores arbitrariamente grandes. 1 La solución: intercalar sus bits y almacenar el número de combinación resultante en el acumulador. Por ejemplo, un valor de acumulador de 6437 almacenaría los siguientes datos (utilizando el bit de orden más bajo como un indicador de un solo bit):
Podemos acceder a cualquier bit de cualquier número dividiendo el acumulador por la potencia apropiada de 2, mod 2. Esto también permite configurar o voltear bits individuales.
En el nivel macro, el algoritmo recorre los números unarios en la entrada. Lee un valor en el número 0, luego pasa el algoritmo de clasificación de burbujas para colocarlo en la posición correcta en comparación con los otros tres números. Finalmente, descarta el valor que queda en el número 0, ya que ahora es el más pequeño de los cuatro y nunca puede ser el tercero más grande. Cuando finaliza el ciclo, el número 1 es el tercero más grande, por lo que descartamos los demás y lo enviamos.
La parte más difícil (y la razón por la que tuve variables de bucle global en la primera encarnación) es comparar dos números para saber si intercambiarlos. Para comparar dos bits, podemos convertir una tabla de verdad en una expresión matemática; mi avance para Acc !! estaba encontrando un algoritmo de comparación que procedía de bits de orden bajo a orden alto, ya que sin variables globales no hay forma de recorrer los bits de un número de izquierda a derecha. El bit de orden más bajo del acumulador almacena una bandera que indica si se intercambian los dos números actualmente en consideración.
Sospecho que Acc !! es Turing completo, pero no estoy seguro de querer tomar la molestia de probarlo.
Aquí está mi solución con comentarios:
1 Según la especificación de la pregunta, solo se deben admitir valores de hasta 1 millón. Me alegra que nadie haya aprovechado eso para una solución más fácil, aunque no estoy completamente seguro de cómo harían las comparaciones.
fuente
Picofuck (seguro)
Picofuck es similar a Smallfuck . Funciona en una cinta binaria que está desatada a la derecha, unida a la izquierda. Tiene los siguientes comandos:
>
mover el puntero a la derecha<
mueve el puntero hacia la izquierda. Si el puntero se cae de la cinta, el programa termina.*
voltear el bit en el puntero(
si el bit en el puntero es0
, salta al siguiente)
)
no hacer nada: los paréntesis en Picofuck sonif
bloques, nowhile
bucles..
escriba para stdout el bit en el puntero como un ascii0
o1
.,
leemos desde stdin hasta que encontramos un0
o1
, y almacenamos esto en el bit en el puntero.Envolturas de código Picofuck: una vez que se alcanza el final del programa, continúa desde el principio.
Además, Picofuck no permite paréntesis anidados. Los paréntesis que aparecen en un programa Picofuck deben alternar entre
(
y)
, comenzando(
y terminando con)
.Interprete
Escrito en Python 2.7
uso:
python picofuck.py <source_file>
Solución
El siguiente programa de Python 2.7 genera mi solución que se puede encontrar aquí
Puedo editar esta publicación más adelante con una explicación más detallada de cómo funciona, pero resulta que Picofuck está completo de Turing.
fuente
PQRS - ¡Seguro! / Solución proporcionada
Lo esencial
Todas las instrucciones implícitas tienen cuatro operandos de dirección de memoria:
¿Dónde
v
está el tamaño de la memoria en los cuartetos?Pᵢ
,Qᵢ
,Rᵢ
,Sᵢ
Son números enteros de tamaño nativo de la máquina firmado (por ejemplo, 16, 32 o 64 bits), que nos referiremos como palabras.Para cada cuarteto
i
, la operación implícita, con[]
denotar indirección, es:Tenga en cuenta que Subleq es un subconjunto de PQRS .
Subleq ha demostrado ser completo, por lo que PQRS también debería estar completo.
Estructura del programa
PQRS define un encabezado inicial de la siguiente manera:
H₀ H₁ H₂ H₃
Es siempre la primera instrucciónP₀ Q₀ R₀ S₀
.H₀
queH₃
deben definirse en tiempo de carga.PQRS tiene E / S rudimentaria, pero suficiente para el desafío.
H₄ H₅
: al inicio del programa, lee un máximo deH₅
caracteres ASCII de la entrada estándar y se guarda como palabras en el índice enH₄
adelante.H₄
yH₅
deben definirse en el momento de la carga. Después de leer,H₅
se establecerá el número de caracteres leídos (y las palabras guardadas).H₆ H₇
: al finalizar el programa, comenzando en el índiceH₆
, imprime todos los bytes que comprenden lasH₇
palabras a la salida estándar como caracteres ASCII.H₆
yH₇
debe definirse antes de que finalice el programa.'\0'
Se omitirán los bytes nulos en la salida.Terminación
La terminación se logra estableciendo
Sᵢ
límitesi < 0
oi ≥ v
.Trucos
Los cuartetos
Pᵢ Qᵢ Rᵢ Sᵢ
no necesitan estar alineados o secuenciales, se permite la ramificación a intervalos de sub-cuarteto.PQRS tiene indirección, por lo que, a diferencia de Subleq, hay suficiente flexibilidad para implementar subrutinas.
¡El código puede modificarse automáticamente!
Interprete
El intérprete está escrito en C:
Para usar, guarde lo anterior como pqrs.c y luego compile:
Programa de muestra
Los ecos ingresan hasta 40 caracteres, precedidos por 'PQRS-'.
Para ejecutar, guarde lo anterior como
echo.pqrs
, entonces:Ejecutando los casos de prueba:
Todos los casos de prueba se ejecutan extremadamente rápido, por ejemplo, <500 ms.
El reto
PQRS puede considerarse estable, por lo que el desafío comienza 2015-10-31 13:00 y termina 2015-11-08 13:00, veces en UTC.
¡Buena suerte!
Solución
El lenguaje es bastante similar al utilizado en "Baby" , la primera máquina digital electrónica de programas almacenados del mundo. ¡En esa página hay un programa para encontrar el factor más alto de un entero en menos de 32 palabras de memoria (CRT!)!
Descubrí que escribir la solución para cumplir con las especificaciones no era compatible con el sistema operativo y la máquina que estaba usando (un derivado de Linux Ubuntu en hardware un poco más antiguo). Solo estaba solicitando más memoria de la disponible, y volcado del núcleo. En sistemas operativos con administración avanzada de memoria virtual o máquinas con al menos 8 GB de memoria, probablemente pueda ejecutar la solución según las especificaciones. He proporcionado ambas soluciones.
Es muy difícil codificar en PQRS directamente, similar al lenguaje de máquina de escribir, tal vez incluso microcódigo. En cambio, es más fácil escribir en una especie de lenguaje ensamblador que "compilarlo". A continuación se muestra el lenguaje ensamblador anotado para la solución optimizada para ejecutar los casos de prueba:
Lo que hace es analizar la entrada, convirtiendo unario a binario, luego una burbuja ordenando los números con los valores en orden decreciente, y finalmente genera el tercer valor más grande convirtiendo el binario de nuevo en unario.
¡Tenga en cuenta que
INC
(incremento) es negativo yDEC
(decremento) es positivo! Donde está usandoL#
oL#+1
asP-
oQ-OP
s, lo que está sucediendo es que está actualizando punteros: incrementando, decrementando, intercambiando, etc. El ensamblador se compiló a mano en PQRS sustituyendo las etiquetas con los desplazamientos. A continuación se muestra la solución optimizada PQRS :El código anterior se puede guardar
challenge-optimized.pqrs
para ejecutar los casos de prueba.Para completar, aquí están las fuentes por especificaciones:
Y solución:
Para ejecutar lo anterior, se necesitará comentar
#define OPTIMIZED
y añadir#define PER_SPECS
enpqrs.c
y recompilar.Este fue un gran desafío, ¡realmente disfruté el entrenamiento mental! Me llevó de vuelta a mis viejos días de ensamblador 6502 ...
Si tuviera que implementar PQRS como un lenguaje de programación "real", probablemente agregaría modos adicionales para acceso directo y doblemente indirecto además del acceso indirecto, así como posición relativa y posición absoluta, ¡ambas con opciones de acceso indirecto para la ramificación!
fuente
¡Zinc agrietado! por @Zgarb
También disponible en GitHub .
Necesitas Dart 1.12 y Pub. Simplemente ejecute
pub get
para descargar la única dependencia, una biblioteca de análisis.¡Esperemos que este dure más de 30 minutos! : O
El idioma
El zinc está orientado a redefinir operadores. ¡Puede redefinir todos los operadores en el idioma fácilmente!
La estructura de un programa típico de zinc se ve así:
Solo hay dos tipos de datos: enteros y conjuntos. No existe un conjunto literal, y los conjuntos vacíos no están permitidos.
Expresiones
Las siguientes son expresiones válidas en Zinc:
Literales
El zinc admite todos los literales enteros normales, como
1
y-2
.Variables
El zinc tiene variables (como la mayoría de los idiomas). Para hacer referencia a ellos, solo use el nombre. De nuevo como la mayoría de los idiomas!
Sin embargo, hay una variable especial llamada
S
que se comporta como PythQ
. Cuando lo use por primera vez, leerá en una línea desde la entrada estándar y lo interpretará como un conjunto de números. Por ejemplo, la línea de entrada1234231
se convertiría en el conjunto{1, 2, 3, 4, 3, 2, 1}
.¡¡¡NOTA IMPORTANTE!!! En algunos casos, un literal al final de una anulación del operador se analiza incorrectamente, por lo que debe rodearse con paréntesis.
Operaciones binarias
Se admiten las siguientes operaciones binarias:
+
:1+1
.-
:1-1
.*
:2*2
./
:4/2
.=
:3=3
.Además, también se admite la siguiente operación unaria:
#
:#x
.La precedencia es siempre correcta asociativa. Puede usar paréntesis para anular esto.
Solo la igualdad y la longitud trabajan en sets. Cuando intenta obtener la longitud de un número entero, obtendrá el número de dígitos en su representación de cadena.
Establecer comprensiones
Para manipular conjuntos, Zinc ha comprendido conjuntos. Se ven así:
Una cláusula es una cláusula when o una cláusula sort.
Una cláusula when parece
^<expression>
. La expresión que sigue al símbolo de intercalación debe dar como resultado un número entero. El uso de la cláusula when tomará solo los elementos del conjunto para los cualesexpression
no es cero. Dentro de la expresión, la variable_
se establecerá en el índice actual del conjunto. Es más o menos equivalente a este Python:Una cláusula de ordenación , que parece
$<expression>
, ordena el conjunto descendiendo por el valor de<expression>
. Es igual a este Python:Aquí hay algunos ejemplos de comprensión:
Tome solo los elementos del conjunto
s
que son iguales a 5:Ordene el conjunto
s
por el valor si sus elementos están al cuadrado:Anulaciones
Las anulaciones de operador le permiten redefinir operadores. Se ven así:
o:
En el primer caso, puede definir un operador para que sea igual a otro operador. Por ejemplo, puedo definir
+
restar realmente a través de:Cuando haces esto, puedes redefinir un operador para que sea un operador mágico . Hay dos operadores mágicos:
join
toma un conjunto y un entero y se une al contenido del conjunto. Por ejemplo, unirse{1, 2, 3}
con4
dará como resultado el entero14243
.cut
también toma un conjunto y un número entero y dividirá el conjunto en cada aparición del número entero. Usandocut
on{1, 3, 9, 4, 3, 2}
y3
creará{{1}, {9, 4}, {2}}
... PERO cualquier conjunto de un solo elemento se aplana, por lo que el resultado será realmente{1, {9, 4}, 2}
.Aquí hay un ejemplo que redefine al
+
operador para que signifiquejoin
:Para el último caso, puede redefinir un operador a la expresión dada. Como ejemplo, esto define la operación más para agregar los valores y luego agregar 1:
Pero lo que es
+:
? Puede agregar los dos puntos:
a un operador para usar siempre la versión incorporada. Este ejemplo usa la+
vía incorporada+:
para sumar los números, luego agrega un 1 (recuerde, todo es asociativo correcto).Anular el operador de longitud se parece a:
Tenga en cuenta que casi todas las operaciones integradas (excepto la igualdad) utilizarán este operador de longitud para determinar la longitud del conjunto. Si lo definiste como:
cada parte de Zinc que funciona en conjuntos, excepto
=
que solo funcionaría en el primer elemento del conjunto que se le dio.Anulaciones múltiples
Puede anular varios operadores separándolos con comas:
Impresión
No puede imprimir directamente nada en Zinc. Se
in
imprimirá el resultado de la siguiente expresión . Los valores de un conjunto se concatenarán con separador. Por ejemplo, toma esto:Si
expr
es el conjunto{1, 3, {2, 4}}
,1324
se imprimirá en la pantalla una vez que finalice el programa.Poniendolo todo junto
Aquí hay un programa simple de Zinc que parece agregar
2+2
pero hace que el resultado sea 5:El interprete
Esto entra en
bin/zinc.dart
:Y esto entra
pubspec.yaml
:Solución prevista
fuente
join
un conjunto mixto{1,{3,2}}
, ¿habrá un error? No puedo instalar Dart en este momento, así que no puedo comprobarlo.dart bin/zinc.dart test.znc
, aparece un error de sintaxis:'file:///D:/Development/languages/zinc/bin/zinc.dart': error: line 323 pos 41: unexpected token '?'
...var input = stdin.readLineSync() ?? '';
-2+#:S
cuando me lo dieronS
, lo que cortó los dos ceros finales. Así era como esperaba que se resolviera. Y^
no se supone que revierta el set ... eso fue un error ... ''Sopa de brújula ( agrietada por cartón_caja )
Intérprete: C ++
Compass Soup es como una máquina de Turing con una cinta infinita de 2 dimensiones. El problema principal es que la memoria de instrucciones y la memoria de datos están en el mismo espacio, y la salida del programa es todo el contenido de ese espacio.
Cómo funciona
Un programa es un bloque de texto bidimensional. El espacio del programa comienza con todo el código fuente colocado con el primer carácter en (0,0). El resto del espacio del programa es infinito y se inicializa con caracteres nulos (ASCII 0).
Hay dos punteros que pueden moverse por el espacio del programa:
!
personaje o en (0,0) si eso no existe.x
,X
,y
, yY
. Comienza en la ubicación del@
personaje o en (0,0) si eso no existe.Entrada
El contenido de stdin se imprime en el espacio del programa comenzando en la ubicación del
>
carácter, o en (0,0) si eso no existe.Salida
El programa termina cuando el puntero de ejecución se ejecuta irremediablemente fuera de los límites. La salida es el contenido completo del espacio del programa en ese momento. Se envía a stdout y 'result.txt'.
Instrucciones
n
- redirige el puntero de ejecución Norte (y negativo)e
- redirige el puntero de ejecución Este (x positivo)s
- redirige el puntero de ejecución Sur (y positivo)w
- redirige el puntero de ejecución Oeste (x negativo)y
- mueve el puntero de datos al Norte (y negativo)X
- mueve el puntero de datos al Este (x positivo)Y
- mueve el puntero de datos al sur (y positivo)x
- mueve el puntero de datos al oeste (x negativo)p
- escribe el siguiente carácter encontrado por el puntero de ejecución en el puntero de datos. Ese personaje no se ejecuta como una instrucción.j
- comprueba el siguiente carácter encontrado por el puntero de ejecución contra el carácter debajo del puntero de datos. Ese personaje no se ejecuta como una instrucción. Si son iguales, el puntero de ejecución salta sobre el siguiente carácter.c
- escribe el carácter nulo en el puntero de datos.*
- punto de interrupción: solo hace que el intérprete se rompa.El puntero de ejecución ignora todos los demás caracteres.
Interprete
El intérprete toma el archivo fuente como argumento y entrada en stdin. Tiene un depurador steppable, que puede invocar con una instrucción de punto de interrupción en el código (
*
). Cuando está roto, el puntero de ejecución se muestra como ASCII 178 (bloque sombreado más oscuro) y el puntero de datos se muestra como ASCII 177 (bloque sombreado más claro).Ejemplos
Hola Mundo
Gato
Paridad: acepta una cadena de caracteres terminados en cero ('0'). Salidas
yes
en la primera línea de la salida si el número de 1s en la entrada es impar, de lo contrario salidas|
.Consejos
Debe usar un buen editor de texto y hacer un uso juicioso de la funcionalidad de la tecla 'Insertar', y usar 'Alt-Drag' para agregar o eliminar texto en varias filas a la vez.
Solución
Aquí está mi solución. No es tan bueno como cartón_box porque tuve que hacer que el código fuente se elimine solo. También esperaba poder encontrar una manera de eliminar todo el código y dejar solo la respuesta, pero no pude.
Mi enfoque fue dividir las diferentes secuencias de
1
s en diferentes líneas, luego ordenarlas haciendo que1
todas las s "caigan" hasta que golpeen a otra1
, y finalmente borrar todo excepto la tercera línea después de la entrada.#A#
lee1
s y los copia en la última línea de la división hasta que0
se lee a.#B#
comprueba por un segundo0
y va hacia el norte hasta que#D#
haya uno. De lo contrario,#C#
comienza una nueva línea dividida colocando|
después de la última y vuelve a#A#
.#F#
es el código de gravedad. Camina hasta el final1
de la primera fila y lo mueve hacia arriba hasta que golpea1
o-
. Si no puede hacer eso, marca la fila como terminada poniéndola+
antes.#G#
está borrando todas las divisiones innecesarias y#H#
está borrando stdin y todo el código entre paréntesis.Código:
fuente
c
al principio que no debería haber estado allí. Lo arreglé. También agregué mi solución al problema.Acc! , Cracc'd por ppperry
Este lenguaje tiene una estructura de bucle, matemática entera básica, E / S de caracteres y un acumulador (de ahí el nombre). Solo un acumulador. Por lo tanto, el nombre.
Declaraciones
Los comandos se analizan línea por línea. Hay tres tipos de comando:
Count <var> while <cond>
Counts
<var>
hasta de 0, siempre y cuando<cond>
es distinto de cero, equivalente a C-estilofor(<var>=0; <cond>; <var>++)
. El contador de bucle puede ser cualquier letra minúscula. La condición puede ser cualquier expresión, que no implique necesariamente la variable de bucle. El ciclo se detiene cuando el valor de la condición se convierte en 0.Los bucles requieren llaves rizadas de estilo K y R (en particular, la variante Stroustrup ):
Write <charcode>
Emite un solo carácter con el valor ASCII / Unicode dado a stdout. El código de char puede ser cualquier expresión.
Cualquier expresión en sí misma se evalúa y se asigna de nuevo al acumulador (al que se puede acceder como
_
). Por lo tanto, por ejemplo,3
es una declaración que establece el acumulador en 3;_ + 1
incrementa el acumulador; y_ * N
lee un personaje y multiplica el acumulador por su código de char.Nota: el acumulador es la única variable a la que se puede asignar directamente; variables de bucle y
N
se pueden usar en cálculos pero no se pueden modificar.El acumulador es inicialmente 0.
Expresiones
Una expresión puede incluir literales enteros, variables de bucle (
a-z
),_
para el acumulador y el valor especialN
, que lee un carácter y evalúa su código de caracteres cada vez que se usa. Nota: esto significa que solo tienes una oportunidad para leer cada personaje; la próxima vez que lo usesN
, leerás el siguiente.Los operadores son:
+
, además-
resta negación unaria*
multiplicación/
, División entera%
módulo^
exponenciaciónLos paréntesis pueden usarse para imponer la precedencia de las operaciones. Cualquier otro carácter en una expresión es un error de sintaxis.
Espacio en blanco y comentarios
Los espacios en blanco iniciales y finales y las líneas vacías se ignoran. El espacio en blanco en los encabezados del bucle debe ser exactamente como se muestra, con un solo espacio entre el encabezado del bucle y la llave de apertura. El espacio en blanco dentro de las expresiones es opcional.
#
comienza un comentario de una sola línea.De entrada y salida
Acc! espera una sola línea de caracteres como entrada. Cada carácter de entrada se puede recuperar en secuencia y su código de char procesado usando
N
. Intentar leer más allá del último carácter de la línea provoca un error. Se puede generar un carácter pasando su código de char a laWrite
instrucción.Interprete
El intérprete (escrito en Python 3) traduce Acc! codifique en Python y
exec
listo.fuente
GoToTape (seguro)
(Anteriormente conocido como Simp-plex.)
Este lenguaje es simple. El control de flujo principal es goto, la forma de control más natural y útil.
Especificación de idioma
Los datos se almacenan en una cinta y en un acumulador. Funciona completamente con integrados sin firmar. Cada personaje es comando. Los siguientes son todos los comandos:
a
-z
son declaraciones de goto que van aA
-Z
, respectivamente.:
: establece el acumulador en el valor ASCII en char desde la entrada.~
: genera el carácter para el valor ASCII en el acumulador.&
: reste uno del acumulador si es 1 o más, de lo contrario agregue uno.|
: agrega uno al acumulador.<
: establece el puntero de datos a 0.+
: incrementa la celda de datos en el puntero de datos; mueve el puntero +1.-
: resta uno de la celda de datos en el puntero de datos si es positivo; mueve el puntero +1.[...]
: ejecuta el código n veces donde n es el número en la cinta en el puntero de datos (no se puede anidar)./
: omita la siguiente instrucción si el acumulador es 0.Intérprete (C ++)
¡Que te diviertas!
Solución
A:+&&&&&&&&&&/gbG&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&/a<aB<[|]C[&]-[|]/c<[|]D[&]-[|]/d<[|]+E[&]|||||||||||||||||||||||||||||||||||||||||||||||||~X&/x-[|]/e
fuente
calloc
lugar denew char
, escribió un bucle while de estilo C, usó la administración de memoria de estilo C, nos hizo volver a compilar el archivo C ++ cada vez que cambiamos el código y usamos 20 ifs en lugar de aswitch
? No me quejo, pero mis ojos están sangrando en este momento ...: Ostr.c_str()
para obtener unchar*
.Esta fue una mala idea ya que casi todos los lenguajes esotéricos parecen ilegibles (mira Jelly).
Pero aquí va:
Pylongolf2 beta6
Empujando a la pila
Empujar a la pila actúa de manera diferente que en otros idiomas.
El código
78
empuja7
y8
entra en la pila, sin embargo, en Pylongolf empuja78
.En Pylongolf2 esto se puede alternar con
Ü
.Comandos
Concatenación de cadenas y eliminación de un patrón de expresiones regulares de una cadena
El símbolo + concatena cadenas.
Puede usar el símbolo - para eliminar caracteres que siguen un patrón de expresiones regulares de una cadena:
Este código toma datos y elimina todos los caracteres no alfabéticos al eliminar todas las coincidencias de patrones
[^a-zA-Z]
.El elemento seleccionado debe ser la expresión regular y el anterior debe ser la cadena para editar.
Si declaraciones
Para hacer declaraciones if, ponga un
=
para comparar el elemento seleccionado y el siguiente.Esto coloca a
true
o afalse
en su lugar.El comando
?
comprueba este booleano.Si es así,
true
no hace nada y el intérprete continúa.Si es así,
false
el intérprete salta al¿
personaje más cercano .Tomado de la página de Github.
Intérprete para Pylongolf2 (Java):
fuente
Rainbow (Nota: intérprete próximamente)
Sé que este desafío expiró.
Rainbow es una mezcla de ... muchas cosas.
Rainbow es un lenguaje basado en la pila 2D con dos pilas (Like Brain-Flak) y 8 direcciones (
N NE E SE S SW W NW
). Hay 8 comandos:1
,+
,*
,"
Hacer exactamente lo que hacen en 1+.!
alterna la pila activa.>
gire la IP en sentido horario.,
ingrese un personaje y empújelo..
pop y salida de un personaje.Sin embargo, los caracteres en el código fuente no se ejecutan inmediatamente. En cambio,
[The Character in the source code]^[Top Of Stack]
se alimenta en la conjetura de Collatz, y la cantidad de pasos que se necesitan para llegar a 1 se convierte en un carácter por la tabla ASCII. Este personaje luego se ejecuta.Al comienzo del programa, el código fuente (excepto el último carácter) se inserta en la pila.
Cuando la IP llega al borde del código fuente, termina.
Apocalipsis
nym son dos registros. Cuando
>
se ejecuta una instrucción, m se incrementa. Apocalipsis solo se activa si m excede n. Cuando sucede Apocalipsis:m es inicialmente cero, y n es inicialmente el último carácter del código fuente.
Cifrado
Después de ejecutar cualquier ejecución, el código fuente se cifra. El ASCII del primer personaje se incrementa en uno, el segundo se reduce en uno, el tercero se incrementa en dos, el cuarto se reduce en dos, etc.
fuente