Tu desafío es simple. Escriba dos programas que no compartan caracteres que se muestren entre sí
Ejemplo
Dos programas P y Q son quines mutuamente excluyentes si:
- P salidas Q
- Q salidas P
- No hay un carácter c que pertenezca tanto a P como a Q
- Cada programa P y Q son quines adecuados
- Esto cuenta las quines vacías y las quines que leen su propio código fuente (o el del otro) como inválido .
Más reglas
- La duración combinada más corta de estos programas gana. Es decir, el tamaño ( P ) + tamaño ( Q ) es su puntaje, y gana el puntaje más bajo.
- Ambos programas están en el mismo idioma.
- Cada programa puede ser un programa completo o una función, y no necesitan ser lo mismo.
- Por ejemplo, P puede ser un programa completo y Q puede ser una función.
Verificación
¡ Pruébalo en línea! El fragmento aquí puede verificar si dos programas son mutuamente excluyentes. Las entradas se ponen en los dos primeros argumentos.
code-challenge
quine
Conor O'Brien
fuente
fuente
Respuestas:
> <> , Puntuación: 41 + 41 = 82
Editar: ambos contenían un 3. Corregido
y
Pruébalo en línea! (intercambie las líneas para obtener el otro resultado) ¡ Con verificación esta vez!
><>
es un lenguaje especialmente difícil de usar aquí, ya que solo hay una forma de generar caracteres, el comandoo
. Afortunadamente, podemos usar el comando p ut para colocar uno
en el código fuente durante la ejecución, como en mi respuesta Programación en un mundo prístino.Éste tomó mucha prueba y error. Comencé con los dos programas mutuamente excluyentes:
y
Cada uno se transforma a sí mismo y sus datos en N, el primero restando y el segundo sumando. Luego emite esto a la inversa. El punto es que los datos después de cada programa son el otro programa en reversa, desplazado por N. (
X
es el número de celda donde el programa necesita poner elo
e Y es la celda donde el puntero regresa.?
Es dondeo
se pone el) .Ambos siguen la misma estructura, representada de diferentes maneras. Ejecutan un literal de cadena sobre todo el código y lo agregan a la pila. Recrean el comando literal de cadena que usaron y lo colocan en la parte inferior de la pila. Se desplazan sobre la pila, sumando / restando N a cada personaje e imprimiéndolos.
El primer programa usa
'
como literal de cadena, y el simpled3*}
para crear el valor 39 y empujarlo al final de la pila. El segundo usa"
como literal de cadena con la misma función. Ser
everses la pila,g
ets el carácter en la celda 0,0 y revierte la pila de nuevo. Luegog
obtiene el valor en la celda 4,0 (g
) y le agrega 8 para obtenero
y lo pone en X.Ambos programas usan un método diferente de bucle. El primer programa usa el comando skip (
!
) para ejecutar solo la mitad de las instrucciones mientras se dirige hacia la izquierda, invierte la dirección y ejecuta la otra mitad. El segundo usa el comando de salto (.
) para saltar hacia atrás al inicio del ciclo en la celda Y. Ambos se ejecutan hasta que no hay más elementos en la pila y los errores del programa.Me encontré con una serie de problemas con la mayoría de los valores más bajos de N, porque cambiar un carácter lo convertiría en otro carácter esencial para ese programa (y, por lo tanto, no podría usarse como datos para el otro programa) o dos caracteres del dos programas cambiarían al mismo personaje. Por ejemplo:
+
+1 =,
=-
-1.
+2 =0
*
=-
-3g
+4 =k
=o
-4etc.
Finalmente llegué a 10 (
a
), donde pude evitar estos problemas. Puede haber una versión más corta en la que se invierten los cambios, y el primer programa agrega N mientras que el segundo lo resta. Sin embargo, esto podría ser peor, ya que el primer programa generalmente está en el extremo inferior de la escala ASCII, por lo que restar es mejor para evitar conflictos.fuente
Adelante (gforth little endian de 64 bits) , 428 + 637 = 1065 bytes
Pruébalo en línea!
Script de verificación
Gracias a @Nathaniel por la idea de usar Forth, me recordó en los comentarios que Forth no distingue entre mayúsculas y minúsculas . Luego vinieron los cambios de humor: he encontrado razones por las que esto no funcionará, seguido de soluciones a estos problemas, una y otra vez. Todo mientras hago girar mi bicicleta de entrenamiento en interiores como una ruleta intranquila al revés y deformada (solo tienes que agarrar un extremo del manillar e inclinarlo un poco).
Antes de escribir estos programas, redacté qué caracteres pueden ser utilizados por cada programa. Específicamente, el segundo programa solo puede usar letras mayúsculas, dígitos decimales, tabulaciones y comas. Esto significaría que el primer programa es todo en minúsculas, pero usé algunas letras mayúsculas para sus valores ASCII.
Debido a que las pestañas son difíciles de manejar, en su lugar usaré espacios en la explicación.
El primer programa tiene la forma
s" code"code
:s"
comienza un literal de cadena, que luego es procesado por la segunda copia del código, un marco de trabajo estándar. Sin embargo, en lugar de generar su propio código fuente, creará el otro programa, que se ve así:HERE
64-bit-number-literal ,
length-of-the-string
115 EMIT 34 EMIT 9 EMIT 2DUP TYPE 34 EMIT TYPE
Esto usa el espacio de datos de Forth.
HERE
devuelve el puntero al final del área de espacio de datos actualmente asignada y,
agrega una celda llena de un número. Por lo tanto, los primeros tres puntos pueden verse como un literal de cadena creado usandos"
. Para finalizar el segundo programa:EMIT
genera un carácter dado su valor ASCII, entonces:115 EMIT
imprime en minúsculass
34 EMIT
imprime el carácter de la cita"
9 EMIT
imprime una pestaña2DUP
duplica los dos elementos superiores en la pila( a b -- a b a b )
, aquí está el puntero y la longitud de la cadenaTYPE
imprime una cadena para generar la primera copia del código34 EMIT
imprime la cita de cierre"
y finalmenteTYPE
genera la segunda copia del códigoVeamos cómo funciona el primer programa. En muchos casos, se deben evitar los números, lo que se hace usando la
'x
extensión de sintaxis gforth para literales de caracteres, y algunas veces restando el valor ASCII del espacio, que se puede obtener usandobl
:Para terminar esto, me gustaría decir que intenté usar
EVALUATE
, pero el segundo programa se vuelve más grande que los dos presentados anteriormente. De todos modos, aquí está:Si logra jugar golf lo suficiente como para superar mi
s" ..."...
enfoque, continúe y publíquelo como su propia respuesta.fuente
Perl,
(311 + 630 = 941 bytes)190 + 198 = 388 bytesAmbos programas imprimen a la salida estándar.
El primer programa perl contiene principalmente caracteres ASCII imprimibles y nuevas líneas, y termina exactamente en una nueva línea, pero las dos letras ÿ representan el byte no ASCII \ xFF:
El segundo contiene principalmente bytes no ASCII, incluidos varios caracteres de alto control que se reemplazan por estrellas en esta publicación, y no hay líneas nuevas en absoluto:
Un hexdump del primer programa con
xxd
es:Y un hexdump del segundo programa es:
En el segundo programa, la cadena entre comillas (189 bytes de longitud, delimitada por tildes) es el primer programa completo, excepto la nueva línea final, solo codificada por bits que complementa cada byte. El segundo programa simplemente decodifica la cadena complementando cada uno de los bytes, lo que el
~
operador hace en perl. El programa imprime la cadena decodificada seguida de una nueva línea (elsay
método agrega una nueva línea).En esta construcción, el decodificador del segundo programa usa solo seis caracteres ASCII diferentes, por lo que el primer programa puede ser prácticamente arbitrario, siempre que solo contenga caracteres ASCII y excluya esos seis caracteres. No es difícil escribir ningún programa perl sin usar esos cinco caracteres. La lógica de quine real se encuentra así en el primer programa.
En el primer programa, la lógica de quine utiliza un diccionario de 11 palabras de largo
@f
y ensambla la salida de esas palabras. Las primeras palabras repiten la mayor parte del código fuente del primer programa. El resto de las palabras son caracteres individuales específicos. Por ejemplo, la palabra 5 es una tilde, que es el delimitador para el literal de dos cadenas en el segundo programa. La lista de números entre paréntesis es la receta para las palabras que se imprimirán en qué orden. Este es un método de construcción general bastante ordinario para quines, el único giro en este caso es que las primeras palabras del diccionario se imprimen con sus bytes complementados a nivel de bits.fuente
Haskell , 306 + 624 = 930 bytes
Programa 1: una función anónima que toma un argumento ficticio y devuelve una cadena.
Pruébalo en línea!
Programa 2:
q[[40,...]]
al final es una función anónima que toma un argumento ficticio y devuelve una cadena.Pruébalo en línea!
Conjunto de caracteres 1 (incluye espacio):
Conjunto de caracteres 2 (incluye nueva línea):
Como solo el conjunto 1 contiene caracteres no ASCII, sus bytes UTF-8 también son disjuntos.
Cómo funciona
El programa 1 generalmente se escribe con expresiones lambda, espacios y paréntesis, uso libre de funciones alfanuméricas integradas y con los datos de quine como literales de cadena al final.
a
ob
, que forman secuencias de escape válidas que se realizan de manera circularshow
.a
,b
yc
son las únicas letras minúsculas cuyos códigos ASCII son inferiores a 100, ahorrando un dígito en la codificación numérica utilizada por el programa 2.El programa 2 generalmente se escribe con ecuaciones de función de nivel superior (excepto la anónima final), literales de caracteres y números decimales, sintaxis de lista / rango y operadores, y con los datos de quine como una lista de listas de
Int
s al final.Tutorial, programa 1
b
yc
son los valores de los literales de cadena para el programa 2 y 1, respectivamente, dados como argumentos finales a la expresión lambda.()
es un argumento ficticio únicamente para satisfacer la regla de PPCG de que el programa debe definir una función.foldr(\a->map pred)b(show()>>c)
decodifica la cadenab
al código central del programa 2 aplicándolomap pred
varias veces igual a la longitud deshow()>>c == c++c
, o182
.tail(show c)
convierte la cadenac
al código central del programa 1, con una doble comilla final añadida.:pure b
combina esto en una lista con la cadenab
.map(map fromEnum)$
Convierte las cadenas en listas de puntos de código.`mappend`show(...)
serializa la lista de listas resultante y finalmente la agrega al código central del programa 2.Tutorial, programa 2
z~z=[[['@','0'..]!!4..]!!z]
es una función que convierte los puntos de código en caracteres (necesarios para escribir, ya que no todos los caracterestoEnum
están disponibles).z
. El marcador de pereza~
no tiene efecto en esta posición, pero evita un carácter de espacio.['@','0'..]
es un rango de lista de pasos hacia atrás que comienza en el código ASCII 64, y luego salta 16 en cada paso!!4
esto da un\NUL
carácter.[ ..]
rango proporciona una lista de todos los caracteres, que!!z
indexa.z
sobre listas usando en=<<
lugar de las no disponiblesmap
y<$>
.q[x,q]_=z=<<x++q++[34,34]++x
es una función que construye el programa 1 de la lista de datos de quine.x
son los datos para el núcleo del programa 1 (incluida una comilla doble final) y el internoq
son los datos ofuscados para el núcleo del programa 2._
es otro argumento ficticio únicamente para hacer que la función anónima final sea una función en lugar de solo una cadena.x++q++[34,34]++x
concatena las piezas, incluidas dos comillas dobles con código ASCII 34.z=<<
construye el programa 1 mapeandoz
sobre la concatenación para convertir de puntos de código a caracteres.q[[40,...]]
es una función anónima que se combinaq
con los datos de quine.fuente
Gelatina ,
128 90 87 86 85 7916 + 32 = 48 bytesPruébalo en línea!
Pruébalo en línea!
El primer programa hace lo siguiente:
Esto deja las cadenas
79,7806,8318,7885,7769,338,115
yỌṘ
como los dos argumentos de la cadena y están implícitamente concatenados e impresos al final.El segundo programa calcula el
chr
(Ọ
) de la lista de números que devuelveOṾ⁾ọṙŒs
.Ṙ
imprime“OṾ⁾ọṙŒs”
(con comillas) y devuelve la entrada, dejando“OṾ⁾ọṙŒs”OṾ⁾ọṙŒs
como salida completa.fuente
Gol> <> ,
23 + 23 = 4622 + 22 = 4420 + 20 = 40 bytesPruébalo en línea!
Pruébalo en línea!
¡Verifíquelo en línea!
Cómo trabajan ellos
Adaptado de la respuesta de Jo King> <> . Al tener muchos más comandos alternativos para salida y repetición, no hubo necesidad de
g
op
, y los dos cuerpos principales se hicieron mucho más cortos.Otra diferencia principal es que genero la cita del oponente directamente en la parte superior de la pila. De esta manera, era un poco más fácil mantener el invariante
quote + my code + opponent code(reversed and shifted)
.fuente