Como debería saber (con suerte), una quina endurecida por radiación es una quine de la que puede eliminar cualquier carácter y aún imprimir su fuente original, previamente modificada. La cuestión es que con la mayoría de estos solo puedes eliminar un personaje; de lo contrario, todo se rompe. Aquí es donde entra esto; su objetivo es construir una quine endurecida por radiación que pueda eliminar la mayor cantidad de caracteres posible. Cualquier lenguaje que cumpla con las reglas está bien.
Reglas
- El programa debe tener al menos un carácter
- El idioma utilizado debe estar completo (por lo que los idiomas como HQ9 + no califican)
- Todas las demás reglas que se aplican a las cuotas normales también se aplican aquí.
- La solución con el mínimo
program_length^(2/n)
en el que se puede eliminar cualquier conjunto den
caracteres exactos mientras se sigue imprimiendo el código fuente original gana.
Subleq
. ¡Creo que sería ideal para este tipo de desafío!Respuestas:
Perl,
11161124 bytes, n = 3, puntaje = 1124 ^ (2/3) o aproximadamente 108.1Actualización : ahora he verificado que esto funciona con n = 3 a través de la fuerza bruta (que tomó un par de días); con un programa tan complejo, es difícil verificar la resistencia a la radiación a mano (y cometí un error en una versión anterior, por lo que aumentó el recuento de bytes). Fin de actualización
Recomiendo redirigir stderr a algún lugar que no lo vea; Este programa produce un montón de advertencias sobre la sintaxis dudosa, incluso cuando no está eliminando caracteres de la misma.
Es posible que el programa se pueda acortar. Trabajar en esto es bastante doloroso, lo que hace que sea fácil pasar por alto posibles micro optimizaciones. Principalmente tenía el objetivo de obtener el mayor número posible de caracteres eliminables (porque esa es la parte realmente desafiante del programa), y traté el desempate del código de golf como algo que era bueno apuntar pero como algo que no pondría esfuerzo ridículo para optimizar (sobre la base de que es muy fácil romper la resistencia a la radiación por accidente).
El programa
Nota: hay un
_
carácter de control literal (ASCII 31) inmediatamente antes de cada una de las cuatro ocurrencias de-+
. No creo que se haya copiado y pegado correctamente en StackOverflow, por lo que deberá volver a agregarlo antes de ejecutar el programa.La explicación
Este programa está, claramente, compuesto por cuatro programas idénticos más pequeños concatenados juntos. La idea básica es que cada copia del programa verificará si se ha dañado demasiado o no para ejecutarse; si lo ha sido, no hará nada (aparte de posiblemente arrojar advertencias) y dejará que se ejecute la próxima copia; si no lo ha sido (es decir, sin eliminaciones, o el carácter que se eliminó fue uno que no hace ninguna diferencia en la operación del programa), hará su cosa (imprimiendo el código fuente del programa completo; esta es una quine adecuada, con cada parte que contiene una codificación del código fuente completo) y luego salga (evitando que cualquier otra copia no dañada vuelva a imprimir el código fuente y arruinando la quine al imprimir demasiado texto).
Cada parte está hecha a su vez de dos partes que son efectivamente funcionalmente independientes; un contenedor externo y algo de código interno. Como tal, podemos considerarlos por separado.
Envoltura exterior
El envoltorio exterior es, básicamente,
eval<+eval<+eval< ... >####>####...>###
(además de un montón de puntos y comas y líneas nuevas cuyo propósito debería ser bastante obvio; es asegurar que las partes del programa permanezcan separadas independientemente de si algunos de los puntos y comas o las nuevas líneas anteriores se eliminan) ) Esto puede parecer bastante simple, pero es sutil de varias maneras, y la razón por la que elegí a Perl para este desafío.Primero, veamos cómo funciona el contenedor en una copia intacta del programa.
eval
analiza como una función incorporada, que toma un argumento. Debido a que se espera una discusión,+
aquí hay un unario+
(que será muy familiar para los golfistas de Perl por ahora; son útiles sorprendentemente a menudo). Todavía estamos esperando un argumento (acabamos de ver un operador unario), por lo<
que lo que viene a continuación se interpreta como el inicio de la<>
operador (que no toma argumentos de prefijo o postfijo, y por lo tanto puede usarse en la posición del operando).<>
Es un operador bastante extraño. Su propósito habitual es leer los identificadores de archivo y coloca el nombre del identificador de archivo dentro de los corchetes angulares. Alternativamente, si la expresión no es válida como un nombre de identificador de archivo, se bloquea (básicamente, el mismo proceso que usan los shells de UNIX para traducir el texto ingresado por el usuario a una secuencia de argumentos de línea de comandos; en realidad, se usaban versiones mucho más antiguas de Perl) la cáscara para esto, pero hoy en día Perl maneja el globbing interno). El uso previsto, por lo tanto, está en la línea de<*.c>
, que normalmente devolvería una lista como("foo.c", "bar.c")
. En un contexto escalar (como el argumento paraeval
), solo devuelve la primera entrada que encuentra la primera vez que se ejecuta (el equivalente del primer argumento), y devolvería otras entradas en ejecuciones hipotéticas futuras que nunca suceden.Ahora, los shells a menudo manejan argumentos de línea de comandos; si da algo como
-r
sin argumentos, simplemente se pasará al programa textualmente, independientemente de si hay un archivo con ese nombre o no. Perl actúa de la misma manera, por lo tanto, siempre y cuando nos aseguremos de que no haya caracteres que sean especiales para el shell o para Perl, es casi imposible; Parece que hay dos capas de escape con cada<
y la coincidencia>
, podemos usar esto de manera efectiva como una forma realmente incómoda de literal de cadena. Aún mejor, el analizador de Perl para operadores tipo comillas tiene una tendencia compulsiva a emparejar paréntesis incluso en contextos como este donde no tiene sentido, por lo que podemos anidar de<>
forma segura (que es el descubrimiento necesario para que este programa sea posible). El principal inconveniente de todos estos anidados<>
es que escapar de los contenidos de la<>
<>
, por lo que para escapar de algo en el interior de las tres, debe ir precedido de 63 barras diagonales inversas. Decidí que, aunque el tamaño del código es solo una consideración secundaria en este problema, casi seguro que no valía la pena pagar este tipo de penalización, así que decidí escribir el resto del programa sin usar los caracteres ofensivos.Entonces, ¿qué sucede si se eliminan partes del contenedor?
eval
hacen que se convierta en una palabra desnuda , una cadena sin significado. A Perl no le gustan estos, pero los trata como si estuvieran rodeados de comillas; asíeal<+eval<+...
se interpreta como"eal" < +eval<+...
. Esto no tiene ningún efecto en la operación del programa, porque básicamente solo toma el resultado de las evaluaciones muy anidadas (que no usamos de todos modos), lo convierte en un número entero y hace algunas comparaciones sin sentido en él. (Este tipo de cosas causa una gran cantidad de spam de advertencia, ya que claramente no es algo útil en circunstancias normales; solo lo estamos usando para absorber eliminaciones). Esto cambia la cantidad de corchetes angulares de cierre que necesitamos (porque el corchete de apertura ahora se está interpretando como un operador de comparación), pero la cadena de comentarios al final asegura que la cadena terminará de manera segura sin importar cuántas veces esté anidada. (Hay más#
signos de los estrictamente necesarios aquí; lo escribí como lo hice para hacer que el programa sea más compresible, permitiéndome usar menos datos para almacenar el quine).<
se elimina un, el código ahora se analiza comoeval(eval<...>)
. El secundario, externo,eval
no tiene ningún efecto, porque los programas que estamos evaluando no devuelven nada que tenga ningún efecto real como programa (si regresan normalmente, normalmente es una cadena nula o una palabra simple; más comúnmente regresan a través de excepción, que haceeval
que se devuelva una cadena nula, o se usaexit
para evitar el retorno).+
se elimina un, esto no tiene efecto inmediato si el código adyacente está intacto; Unary+
no tiene ningún efecto en el programa. (La razón por la que+
están los s originales es para ayudar a reparar el daño; aumentan el número de situaciones en las que<
se interpreta como un operador unario en<>
lugar de como un operador relacional, lo que significa que necesita más eliminaciones para producir un programa no válido).El contenedor puede dañarse con suficientes eliminaciones, pero debe hacer una serie de eliminaciones para producir algo que no se analice. Con cuatro eliminaciones, puede hacer esto:
y en Perl, el operador relacional
<
no es asociativo y, por lo tanto, se obtiene un error de sintaxis (el mismo con el que se obtendría1<2<3
). Como tal, el límite para el programa tal como está escrito es n = 3. Agregar más+
s unarios parece una forma prometedora de aumentarlo, pero como eso aumentaría la probabilidad de que el interior del contenedor también se rompa, verificando que la nueva versión del programa funcione podría ser muy difícil.La razón por la que el contenedor es tan valioso es que
eval
en Perl detecta excepciones, como (por ejemplo) la excepción que se obtiene cuando intenta compilar un error de sintaxis. Como seeval
trata de un literal de cadena, la compilación de la cadena ocurre en tiempo de ejecución, y si el literal no se compila, la excepción resultante queda atrapada. Esto haceeval
que devuelva una cadena nula y establezca el indicador de error$@
, pero nunca verificamos tampoco (excepto al ejecutar ocasionalmente la cadena nula devuelta en algunas versiones mutadas del programa). Crucialmente, esto significa que si algo le sucede al código dentroel contenedor, causando un error de sintaxis, entonces el contenedor solo hará que el código no haga nada en su lugar (y el programa seguirá ejecutándose en un intento de encontrar una copia no dañada de sí mismo). Por lo tanto, el código interno no tiene que ser tan resistente a la radiación como el envoltorio; todo lo que nos importa es que si está dañado, actuará de forma idéntica a la versión no dañada del programa, o se bloqueará (permitiendoeval
detectar la excepción y continuar) o saldrá normalmente sin imprimir nada.Dentro de la envoltura
El código dentro del contenedor, fundamentalmente, se ve así (de nuevo, hay un Control,
_
que Stack Exchange no mostrará inmediatamente antes del-+
):Este código está escrito completamente con caracteres seguros para glob, y su propósito es agregar un nuevo alfabeto de signos de puntuación que permitan escribir un programa real, a través de la transcripción y evaluación de un literal de cadena (no podemos usarlo
'
o"
como nuestra cita marcas, peroq(
...)
también es una forma válida de formar una cadena en Perl). (La razón del carácter no imprimible es que necesitamos transcribir algo en el carácter de espacio sin un carácter de espacio literal en el programa; por lo tanto, formamos un rango que comienza en ASCII 31 y capturamos el espacio como el segundo elemento del rango). Obviamente, si estamos produciendo algunos caracteres a través de la transliteración, tenemos que sacrificar personajes para transliterarlos de, pero las letras mayúsculas no son muy útiles y es mucho más fácil escribir sin acceso a ellas que sin acceso a signos de puntuación.Aquí está el alfabeto de los signos de puntuación que están disponibles como resultado del globo (la línea superior muestra la codificación, la línea inferior el carácter que codifica):
Lo más notable es que tenemos un montón de signos de puntuación que no son seguros para los globos, pero son útiles para escribir programas de Perl, junto con el carácter de espacio. También guardé dos letras mayúsculas, la literal
A
yZ
(que codifican no para sí mismas, sino paraT
yU
, porqueA
se necesitaba como un punto final de rango superior e inferior); Esto nos permite escribir la instrucción de transliteración en sí usando el nuevo conjunto de caracteres codificados (aunque las letras mayúsculas no son tan útiles, son útiles para especificar cambios en las letras mayúsculas). Los caracteres más notables que no tenemos disponibles son[
,\
y]
, pero ninguno es necesario (cuando necesitaba una nueva línea en la salida, la produje usando la nueva línea implícita desay
en lugar de necesitar escribir\n
;chr 10
también habría funcionado pero es más detallado).Como de costumbre, debemos preocuparnos por lo que sucede si el interior del contenedor se daña fuera del literal de la cadena. Un corrupto
eval
evitará que algo se ejecute; Estamos bien con eso. Si las comillas se dañan, el interior de la cadena no es válido Perl y, por lo tanto, el contenedor lo atrapará (y las numerosas sustracciones en las cadenas significan que incluso si pudieras hacerlo válido Perl, no haría nada, lo que Es un resultado aceptable). El daño a la transliteración, si no se trata de un error de sintaxis, dañará la cadena que se está evaluando, lo que generalmente hace que se convierta en un error de sintaxis; No estoy 100% seguro de que no haya casos en los que esto se rompa, pero lo estoy forzando por el momento para asegurarme, y debería ser lo suficientemente fácil de solucionar si lo hay.El programa codificado
Mirando dentro del literal de cadena, invirtiendo la codificación que utilicé y agregando espacios en blanco para que sea más legible, obtenemos esto (nuevamente, imagine un guión bajo de control antes del
-+
, que está codificado comoA
):Las personas que están acostumbradas a las quines reconocerán esta estructura general. La parte más crucial es al comienzo, donde verificamos que $ o no está dañado; si se han eliminado los personajes, su longitud no coincide
181
, por lo que se correzzzz((()))
el cual, si no es un error de sintaxis debido a los soportes sin igual, será un error de ejecución, incluso si elimina cualquiera de los tres personajes, porque ninguno dezzzz
,zzz
,zz
, yz
es una función, y no hay forma de evitar que se analice como una función que no sea eliminar(((
y causar un error de sintaxis obvio. El cheque en sí también es inmune al daño; la||
pueden dañarse a|
pero eso hará que lazzzz((()))
llamada para funcionar sin condiciones; las variables o constantes dañinas causarán una falta de coincidencia porque estás comparando una de0
,180
,179
,178
por igualdad a algún subconjunto de los dígitos de181
; y eliminar uno=
causará una falla de análisis, y dos=
inevitablemente harán que el LHS evalúe el entero 0 o una cadena nula, los cuales son falsey.Actualización : Esta comprobación fue ligeramente incorrecta en una versión anterior del programa, por lo que tuve que editarla para solucionar el problema. La versión anterior se veía así después de la decodificación:
y fue posible eliminar los primeros tres signos de puntuación para obtener esto:
lengtho179
, siendo una palabra simple, es verdad y, por lo tanto, rompe el control. Lo arreglé agregando dosB
caracteres adicionales (que codifican caracteres de espacio), lo que significa que la última versión de la quine hace esto:Ahora es imposible ocultar tanto los
=
signos como el$
signo sin producir un error de sintaxis. (Tuve que agregar dos espacios en lugar de uno porque una longitud180
pondría un0
carácter literal en la fuente, lo que podría ser abusado en este contexto para comparar cero entero con una palabra desnuda, que tiene éxito). Fin de la actualizaciónUna vez que se pasa la verificación de longitud, sabemos que la copia no está dañada, al menos en términos de eliminaciones de caracteres, por lo que todo es una simple clasificación desde allí (las sustituciones de signos de puntuación debido a una tabla de decodificación corrupta no se detectarán con esta verificación , pero ya he verificado a través de la fuerza bruta que no hay tres eliminaciones de solo la tabla de decodificación que rompen el quine; presumiblemente, la mayoría de ellos causan errores de sintaxis). Ya tenemos
$o
una variable, así que todo lo que tenemos que hacer es codificar los envoltorios externos (con un pequeño grado de compresión; no omití la parte del código de golf de la pregunta por completo ). Un truco es que almacenamos la mayor parte de la tabla de codificación en$r
; podemos imprimirlo literalmente para generar la sección de la tabla de codificación del envoltorio interno, o concatenar un código a su alrededoreval
para ejecutar el proceso de decodificación en reversa (lo que nos permite descubrir cuál es la versión codificada de $ o , teniendo solo la versión decodificada disponible en este momento).Finalmente, si fuéramos una copia intacta y pudiéramos generar el programa original completo, llamamos
exit
para evitar que las otras copias también intenten imprimir el programa.Script de verificación
No es muy bonito, pero lo publica porque alguien preguntó. Ejecuté esto varias veces con una variedad de configuraciones (normalmente cambiando
$min
y$max
para verificar varias áreas de interés); No fue un proceso totalmente automatizado. Tiene tendencia a dejar de funcionar debido a la gran carga de CPU en otros lugares; cuando esto sucedió, simplemente cambié$min
al primer valor$x
que no estaba completamente verificado y continué ejecutando el script (asegurando así que todos los programas en el rango se verificaran eventualmente). Solo verifiqué las eliminaciones de la primera copia del programa, porque es bastante obvio que las eliminaciones de las otras copias no pueden hacer más.fuente
Befunge-98 , 884, n = 14, puntaje ≈ 2.636
Pruébalo en línea!
Esto no solo funciona cuando elimina exactamente 14 caracteres, sino incluso cuando elimina cualquier cantidad de hasta 14 caracteres.
n = 14
Puede parecer una elección muy arbitraria, pero la técnica que utilicé en realidad solo puede usarse para órdenes de endurecimiento de la radiación del 1 al 14, pero no más allá de eso (podría ser posible, pero no tengo idea de cómo). El orden-1 quine es simplemente 73 bytes (aunque emplea algunos trucos de golf que no se aplican a los más grandesn
):Explicación
Cuando estaba trabajando en esta respuesta , descubrí que es posible establecer el delta del puntero de instrucciones en
(2,0)
condiciones de endurecimiento por radiación con el siguiente fragmento:Vea esa respuesta para saber por qué esto funciona. Encontré esto solo con un poco de violín a mano, pero esto planteó la pregunta de si hay patrones similares que sean robustos al eliminar múltiples caracteres. Así que escribí un breve script de Mathematica para buscarlos por fuerza bruta:
Esto reveló muy rápidamente un patrón. Para obtener un fragmento correspondiente que funcione para la eliminación de hasta
n
caracteres, puede usar(m0x){n}m0
wherem
isn+1
yx
is om
o0
. Por lo tanto, todo lo siguiente funcionaría para eliminar hasta dos caracteres:Estoy seguro de que es posible probar esto, pero simplemente lo he verificado
n
hasta7
. Por supuesto, esto solo funciona siempre que podamos representarn+1
como un solo dígito, y el dígito más grande en Befunge 98 es elf
que representa 15. Es por eso que mi enfoque se limita an = 14
. Si alguien encuentra una manera de establecer de manera confiable el delta en más granden+1
, es probable que sea posible aumentar el orden de esta quina endurecida por radiación indefinidamente.Miremos el código real. Básicamente tiene dos partes. Primero configuramos el delta
(15,0)
como acabo de mencionar:Y el resto del código tiene cada comando repetido 15 veces e imprime la fuente. Si eliminamos la repetición, se ve así:
Esta
"
es una técnica de combinación 2D estándar: inicia el modo de cadena, empuja todos los caracteres (excepto a sí mismo) en la pila y finaliza el modo de cadena nuevamente después de ajustar. Esto nos ayuda a obtener todos los puntos de código de la segunda mitad, pero no conseguirá nada útil de la primera mitad, porque a lo largo delf00f00...f0
bit, solo registrará dos caracteres (que pueden serf
o0
dependiendo de qué caracteres se eliminen). ) Pero como esa parte no está compuesta de caracteres que se repiten 15 veces, de todos modos tendremos que imprimirla por separado.Más convenientemente, en la quine no modificada, la longitud de la cadena antes de la
"
es-1 (mod 15)
. Esto garantiza que no importa cuántos caracteres (hasta 14) eliminemos, que la cantidad de caracteres grabados allí siempre es 3 (unox
y dos def
y0
). Esto es realmente cierto para cualquier orden de radiación hasta 14.Ahora comenzamos imprimiendo la
f00f00...f0
pieza:El siguiente
3k$
simplemente descarta eso0
, así como los tres caracteres que fueron empujados"
desde el comienzo del programa. La pila ahora contiene solo los caracteres después del"
, así como algo de basura debajo del original,f00f00...f0
dependiendo de qué caracteres se eliminaron.Ahora solo necesitamos invertir la parte superior de la pila (que contiene los caracteres restantes) e imprimir cada uno de ellos 15 veces.
Y eso es. :)
fuente
JavaScript (ES6), 927 bytes, n = 1, puntaje = 859329
nota: no use un REPL (como una consola del navegador) para ejecutar esto.
Esto se escribió antes de que la longitud del código fuera un factor, por lo que aún no se juega golf.
Esto fue muy difícil y merece una explicación detallada. ¡Lo escribiré más tarde, después de explorar este desafío un poco más!
nota: hay una nueva línea final
Básicamente, la primera línea se construye cuidadosamente para renombrar todas las 'faltas de ortografía' de
setTimeout
las funciones válidas, de modo que si se elimina un carácter de una de lassetTimeout
s, el código no generará errores y la versión indemne puede ejecutarse. También está escrito de modo que si se elimina cualquier carácter de la primera línea, no habrá ningún error y el resto del código puede ejecutarse sin verse afectado.El segundo y tercer bloque son exactamente equivalentes. Si uno se ejecuta hasta su finalización, establece la
_
variable para que el otro sepa que no debe duplicar la quine. Si uno de estos bloques falla, no afecta al otro bloque porque se llamó de forma asincrónicasetTimeout
. El error hará que_
no se establezca, por lo que el otro bloque se eliminará correctamente. El código principal está en una cadena, que se verifica para determinar la longitud en cada bloque para asegurarse de que no haya eliminaciones.Las cadenas de plantilla en la línea siguiente con algunos comentarios al final de las cadenas de plantilla protegen el código de errores si se elimina uno de los backticks que forman la cadena de plantilla. Si se elimina la marca de retroceso final, la cadena de plantilla finaliza con la marca de retroceso en el comentario. Si se elimina el backtick de inicio, setTimeout se evalúa como una función no asignada (un no-op) y el código se ejecuta normalmente, sin setTimeout. El backtick final es anulado por otro comentario.
¿Qué es lo que dices? ¿Quieres probarlo? ¡No digas más!
Modo de página completa recomendado.
Ignora el cuadro de entrada, este fragmento no tiene entrada.
¡Intenta eliminar cualquier carácter del código!
No lo creo El código normal seguirá funcionando (pero no se ajustará ...) ¡Pruebe algo como
console.log(5)
!nota: el fragmento tuvo que modificarse ligeramente para deshabilitar la función REPL, por lo que eliminé varias capacidades de salida solo para esta respuesta.
Una mejor explicación está por llegar. Mientras tanto, ¡siéntase libre de enviarme un correo electrónico al chat @jrich con cualquier comentario / pregunta / crítica!
fuente
this
lugar dewindow
.