Quine endurecida por radiación

39

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 de ncaracteres exactos mientras se sigue imprimiendo el código fuente original gana.
takra
fuente
1
Estoy tratando de encontrar una solución Subleq. ¡Creo que sería ideal para este tipo de desafío!
Relacionado.
Martin Ender
Tal vez cambie el nombre, dado que esto no es lo mismo que una quina endurecida por radiación. ¿Quizás " quine a prueba de radiación "?
Cyoce
@Cyoce La única diferencia que puedo decir es que este desafío es para cualquier cantidad de extracciones, mientras que la mayoría (si no todas) otras quinas endurecidas por radiación solo permiten una.
takra
Solución rubí del famoso "mame". github.com/mame/radiation-hardened-quine
mbomb007

Respuestas:

57

Perl, 1116 1124 bytes, n = 3, puntaje = 1124 ^ (2/3) o aproximadamente 108.1

Actualizació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 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.

eval+<eval+<eval+<eval+(q(FoPqOlengthFoBBPP181XXVVVVJJJKKKNdoWchopJFtPDevalMODx4KNFrPIPA-MN-TUV-ZPINFsPIFoPqOI.Fo.IQNevalFoINevalIFsPZyI.Fr.IT-UPINsayDFtJqJFsKPZyPT-UFWrYrKD.DEEEEQDx6NsayDNDforB1..4YforB1..4NexitQNevalFo)=~y=A-Z=-+;-AZz-~=r)####>####>####>####>####>####>
;
;
;
;
eval+<eval+<eval+<eval+(q(FoPqOlengthFoBBPP181XXVVVVJJJKKKNdoWchopJFtPDevalMODx4KNFrPIPA-MN-TUV-ZPINFsPIFoPqOI.Fo.IQNevalFoINevalIFsPZyI.Fr.IT-UPINsayDFtJqJFsKPZyPT-UFWrYrKD.DEEEEQDx6NsayDNDforB1..4YforB1..4NexitQNevalFo)=~y=A-Z=-+;-AZz-~=r)####>####>####>####>####>####>
;
;
;
;
eval+<eval+<eval+<eval+(q(FoPqOlengthFoBBPP181XXVVVVJJJKKKNdoWchopJFtPDevalMODx4KNFrPIPA-MN-TUV-ZPINFsPIFoPqOI.Fo.IQNevalFoINevalIFsPZyI.Fr.IT-UPINsayDFtJqJFsKPZyPT-UFWrYrKD.DEEEEQDx6NsayDNDforB1..4YforB1..4NexitQNevalFo)=~y=A-Z=-+;-AZz-~=r)####>####>####>####>####>####>
;
;
;
;
eval+<eval+<eval+<eval+(q(FoPqOlengthFoBBPP181XXVVVVJJJKKKNdoWchopJFtPDevalMODx4KNFrPIPA-MN-TUV-ZPINFsPIFoPqOI.Fo.IQNevalFoINevalIFsPZyI.Fr.IT-UPINsayDFtJqJFsKPZyPT-UFWrYrKD.DEEEEQDx6NsayDNDforB1..4YforB1..4NexitQNevalFo)=~y=A-Z=-+;-AZz-~=r)####>####>####>####>####>####>
;
;
;
;

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. evalanaliza 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 -rsin 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?

  • Las eliminaciones en la palabra evalhacen 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).
  • Si <se elimina un, el código ahora se analiza como eval(eval<...>). El secundario, externo, evalno 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 hace evalque se devuelva una cadena nula, o se usa exitpara evitar el retorno).
  • Si +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:

eal<evl<eval+<...

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ía 1<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 evalen Perl detecta excepciones, como (por ejemplo) la excepción que se obtiene cuando intenta compilar un error de sintaxis. Como se evaltrata 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 hace evalque 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á (permitiendo evaldetectar 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 -+):

eval+(q(...)=~y=A-Z=-+;-AZz-~=r)

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, pero q(... )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):

BCDEFGHIJKLMNOPQRSTUVWXYZ
 ! "# $% & '() * +; <=>? @ AZz {|} ~ 

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 Ay Z(que codifican no para sí mismas, sino para Ty U, porque Ase 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 desayen lugar de necesitar escribir \n; chr 10tambié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 evalevitará 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 como A):

$o=q<
  length$o  ==181 || zzzz((()));
  do {
    chop ($t = "eval+<"x4);
    $r = '=-+;-AZz-~=';
    $s = '$o=q<' . $o . '>;eval$o';
    eval '$s=~y' . $r . 'A-Z=';
    say "$t(q($s)=~y=A-Z${r}r)" . "####>"x6;
    say ";" for 1..4
  } for 1..4;
  exit>;
eval $o

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 corre zzzz((()))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 de zzzz, zzz, zz, y zes 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 la zzzz((()))llamada para funcionar sin condiciones; las variables o constantes dañinas causarán una falta de coincidencia porque estás comparando una de 0,180,179, 178por igualdad a algún subconjunto de los dígitos de 181; 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:

length$o==179||zzzz((()))

y fue posible eliminar los primeros tres signos de puntuación para obtener esto:

lengtho179||zzz((()))

lengtho179, siendo una palabra simple, es verdad y, por lo tanto, rompe el control. Lo arreglé agregando dos Bcaracteres adicionales (que codifican caracteres de espacio), lo que significa que la última versión de la quine hace esto:

length$o  ==181||zzzz((()))

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 longitud 180pondría un 0cará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ón

Una 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 $ouna 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 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 alrededor evalpara 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 exitpara 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 $miny $maxpara 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é $minal primer valor $xque 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.

use 5.010;
use IPC::Run qw/run/;
undef $/;
my $program = <>;
my $min = 1;
my $max = (length $program) / 4 - 3;
for my $x ($min .. $max) {
    for my $y ($x .. $max) {
        for my $z ($y .. $max) {
            print "$x, $y, $z\n";
            my $p = $program;
            substr $p, $x, 1, "";
            substr $p, $y, 1, "";
            substr $p, $z, 1, "";
            alarm 4;
            run [$^X, '-M5.010'], '<', \$p, '>', \my $out, '2>', \my $err;
            if ($out ne $program) {
                print "Failed deleting at $x, $y, $z\n";
                print "Output: {{{\n$out}}}\n";
                exit;
            }
        }
    }
}

say "All OK!";

fuente
3
El OP es un poco ambiguo; pero pensé que la puntuación sería (1116 * 1116) / 3.
Greg Martin
@ GregMartin: (1116 * 1116) / 3 es 415152, por lo que esta entrada aún sería ganadora en esas circunstancias. Sin embargo, no creo que el OP pueda significar eso porque daría muy pocos incentivos para poder eliminar varios caracteres. Este quine puede tener menos de la mitad de la longitud si solo lo necesita para manejar la eliminación de un carácter; eso me daría un efectivo ÷ 4 en el puntaje si lo interpretamos así, lo que superaría el ÷ 3 que obtengo de n = 3, y por lo tanto significa que las entradas n = 1 menos interesantes son en realidad mejores puntajes.
2
Hice la puntuación más clara. De todos modos, esto es absolutamente increíble; no pensé que alguien obtendría n> 1.
takra
1
Dice algo sobre Perl que es más fácil escribir un programa sin letras que sin puntuación
Robert Fraser
35

Befunge-98 , 884, n = 14, puntaje ≈ 2.636

f00f00f00f00f00f00f00f00f00f00f00f00f00f00f0xxxxxxxxxxxxxxx"""""""""""""""fffffffffffffff'''''''''''''''000000000000000\\\\\\\\\\\\\\\'''''''''''''''000000000000000\\\\\\\\\\\\\\\'''''''''''''''fffffffffffffff\\\\\\\\\\\\\\\111111111111111---------------:::::::::::::::!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!000000000000000aaaaaaaaaaaaaaa---------------bbbbbbbbbbbbbbb---------------***************jjjjjjjjjjjjjjj$$$$$$$$$$$$$$$'''''''''''''''+++++++++++++++kkkkkkkkkkkkkkk,,,,,,,,,,,,,,,333333333333333kkkkkkkkkkkkkkk$$$$$$$$$$$$$$$000000000000000{{{{{{{{{{{{{{{'''''''''''''''888888888888888uuuuuuuuuuuuuuu'''''''''''''''!!!!!!!!!!!!!!!111111111111111+++++++++++++++'''''''''''''''xxxxxxxxxxxxxxx###############;;;;;;;;;;;;;;;:::::::::::::::!!!!!!!!!!!!!!!kkkkkkkkkkkkkkk@@@@@@@@@@@@@@@dddddddddddddddkkkkkkkkkkkkkkk:::::::::::::::eeeeeeeeeeeeeeekkkkkkkkkkkkkkk,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;

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 = 14Puede 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 grandes n):

200 20 xx""''ÈÈ..aa22**..33kk$$00{{''!!uu''!!11++''xx##;;::!!kk@@::,,,,;;

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:

20020xx

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:

n = 14;
m = 4;
Print @ FromDigits @ {
      m + 1, 0, 
      ## & @@ ((m + 1) IntegerDigits[#, 2, n - 4]),
      m + 1, 0
} & /@ Select[
   Range[0, 2^(n - 4) - 1], 
   AllTrue[
     Subsets[{
         m + 1, 0, 
         ## & @@ ((m + 1) IntegerDigits[#, 2, n - 4]),
         m + 1, 0
       }, 
       {n - m, n - 1}
     ] //. {a___, _, m + 1} | {a___, 0, _} :> {a}, 
     MatchQ@{___, m + 1, 0}
  ] &
];

Esto reveló muy rápidamente un patrón. Para obtener un fragmento correspondiente que funcione para la eliminación de hasta ncaracteres, puede usar (m0x){n}m0where mis n+1y xis o mo 0. Por lo tanto, todo lo siguiente funcionaría para eliminar hasta dos caracteres:

30030030
30030330
30330030
30330330

Estoy seguro de que es posible probar esto, pero simplemente lo he verificado nhasta 7. Por supuesto, esto solo funciona siempre que podamos representar n+1como un solo dígito, y el dígito más grande en Befunge 98 es el fque representa 15. Es por eso que mi enfoque se limita a n = 14. Si alguien encuentra una manera de establecer de manera confiable el delta en más grande n+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:

f00f00f00f00f00f00f00f00f00f00f00f00f00f00f0xxxxxxxxxxxxxxx

Y el resto del código tiene cada comando repetido 15 veces e imprime la fuente. Si eliminamos la repetición, se ve así:

"f'0\'0\'f\1-:!!0a-b-*j$'+k,3k$0{'8u'!1+'x#;:!k@dk:ek,;

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 del f00f00...f0bit, solo registrará dos caracteres (que pueden ser fo 0dependiendo 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 (uno xy dos de fy 0). Esto es realmente cierto para cualquier orden de radiación hasta 14.

Ahora comenzamos imprimiendo la f00f00...f0pieza:

f'0\'0\'f\1-:!!0a-b-*j$'+k,

f          Push 15, a loop counter.
'0\'0\'f\  Put "00f" underneath the loop counter.
1-         Decrement the loop counter.
:!!        Copy it, and turn it into a 1 if it's positive.
0a-b-      Push -21.
*          Multiply by 0 if the loop counter is zero, or by 1 otherwise.
j          Jump that many steps. If the value was 0, this is a no-op and
           the loop ends. Otherwise, this brings us back after the f.
$          Pop the loop counter (which is now 0).
'+k,       Print the top of the stack 43 times, which gives us all of
           the "f00f00...f0" and leaves one "0" on top of the stack.

El siguiente 3k$simplemente descarta eso 0, 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...f0dependiendo 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.

0{     Start a new, empty stack. This pushes two zeros onto the original stack.
'8u    Move the top 56 values from the original stack to the new one, which
       is the 54 characters after the " as well as those two zeros. This is
       implemented as pop-push loop, so it reverses the order of those elements.
'!1+   Push a " by incrementing a !.
'x     Push an x. Now we've got all the characters that are repeated 15 times.
#;     Enter a loop. This is a standard technique for Befunge-98: the ; is
       a bit like a comment character, that ignores everything until the next
       ;, but we jump over the first one with #, so that from now on only
       the code inside will be executed (over and over).
  :!     Copy the top of the stack, and compute logical NOT (1 if 0, 0 otherwise).
  k@     Terminate the program that many times (i.e. when the top of the
         stack is zero).
  dk:    Make 14 copies of the top of the stack.
  ek,    Print 15 characters from the top of the stack.
;

Y eso es. :)

Martin Ender
fuente
16

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!

etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;
setTimeout
`c="function f(){x=String.fromCharCode(96);n=String.fromCharCode(10);q=String.fromCharCode(34);y='etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;'+n;z='setTimeout'+n+x+'c='+q+f+';f();_=1'+q+';if(window._);else if(c.length>339)eval(c)//'+x+'///'+x+n+n;console.log(y+z+z)};f();_=1";if(window._);else if(c.length>339)eval(c)//`///`

setTimeout
`c="function f(){x=String.fromCharCode(96);n=String.fromCharCode(10);q=String.fromCharCode(34);y='etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;'+n;z='setTimeout'+n+x+'c='+q+f+';f();_=1'+q+';if(window._);else if(c.length>339)eval(c)//'+x+'///'+x+n+n;console.log(y+z+z)};f();_=1";if(window._);else if(c.length>339)eval(c)//`///`

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 setTimeoutlas funciones válidas, de modo que si se elimina un carácter de una de las setTimeouts, 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ónica setTimeout. 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.

etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;
setTimeout
`c="function f(){x=String.fromCharCode(96);n=String.fromCharCode(10);q=String.fromCharCode(34);y='etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;'+n;z='setTimeout'+n+x+'c='+q+f+';f();_=1'+q+';if(window._);else if(c.length>339)eval(c)//'+x+'///'+x+n+n;console.log(y+z+z)};f();_=1";if(window._);else if(c.length>339)eval(c)//`///`

setTimeout
`c="function f(){x=String.fromCharCode(96);n=String.fromCharCode(10);q=String.fromCharCode(34);y='etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;'+n;z='setTimeout'+n+x+'c='+q+f+';f();_=1'+q+';if(window._);else if(c.length>339)eval(c)//'+x+'///'+x+n+n;console.log(y+z+z)};f();_=1";if(window._);else if(c.length>339)eval(c)//`///`
<!--                               Try the test suite below!                              --><strong id="bytecount" style="display:inline; font-size:32px; font-family:Helvetica"></strong><strong id="bytediff" style="display:inline; margin-left:10px; font-size:32px; font-family:Helvetica; color:lightgray"></strong><br><br><pre style="margin:0">Code:</pre><textarea id="textbox" style="margin-top:5px; margin-bottom:5px"></textarea><br><pre style="margin:0">Input:</pre><textarea id="inputbox" style="margin-top:5px; margin-bottom:5px"></textarea><br><button id="testbtn">Test!</button><button id="resetbtn">Reset</button><br><p><strong id="origheader" style="font-family:Helvetica; display:none">Original Code Output:</strong><p><div id="origoutput" style="margin-left:15px"></div><p><strong id="newheader" style="font-family:Helvetica; display:none">New Code Output:</strong><p><div id="newoutput" style="margin-left:15px"></div><script type="text/javascript" id="golfsnippet">var bytecount=document.getElementById("bytecount");var bytediff=document.getElementById("bytediff");var textbox=document.getElementById("textbox");var inputbox=document.getElementById("inputbox");var testbtn=document.getElementById("testbtn");var resetbtn=document.getElementById("resetbtn");var origheader=document.getElementById("origheader");var newheader=document.getElementById("newheader");var origoutput=document.getElementById("origoutput");var newoutput=document.getElementById("newoutput");textbox.style.width=inputbox.style.width=window.innerWidth-50+"px";var _originalCode=null;function getOriginalCode(){if(_originalCode!=null)return _originalCode;var allScripts=document.getElementsByTagName("script");for(var i=0;i<allScripts.length;i++){var script=allScripts[i];if(script.id!="golfsnippet"){originalCode=script.textContent.trim();return originalCode}}}function getNewCode(){return textbox.value.trim()}function getInput(){try{var inputText=inputbox.value.trim();var input=eval("["+inputText+"]");return input}catch(e){return null}}function setTextbox(s){textbox.value=s;onTextboxChange()}function setOutput(output,s){output.innerHTML=s}function addOutput(output,data){output.innerHTML='<pre style="background-color:'+(data.type=="err"?"lightcoral":"lightgray")+'">'+escape(data.content)+"</pre>"}function getByteCount(s){return(new Blob([s],{encoding:"UTF-8",type:"text/plain;charset=UTF-8"})).size}function onTextboxChange(){var newLength=getByteCount(getNewCode());var oldLength=getByteCount(getOriginalCode());bytecount.innerHTML=newLength+" bytes";var diff=newLength-oldLength;if(diff>0){bytediff.innerHTML="(+"+diff+")";bytediff.style.color="lightcoral"}else if(diff<0){bytediff.innerHTML="("+diff+")";bytediff.style.color="lightgreen"}else{bytediff.innerHTML="("+diff+")";bytediff.style.color="lightgray"}}function onTestBtn(evt){origheader.style.display="inline";newheader.style.display="inline";setOutput(newoutput,"");setOutput(origoutput,"");var input=getInput();if(input===null){addOutput(origoutput,{type:"err",content:"Input is malformed. Using no input."});addOutput(newoutput,{type:"err",content:"Input is malformed. Using no input."});input=[]}doInterpret(getNewCode(),input,function(data){addOutput(newoutput,data)});doInterpret(getOriginalCode(),input,function(data){addOutput(origoutput,data)});evt.stopPropagation();return false}function onResetBtn(evt){setTextbox(getOriginalCode());origheader.style.display="none";newheader.style.display="none";setOutput(origoutput,"");setOutput(newoutput,"")}function escape(s){return s.toString().replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}window.alert=function(){};window.prompt=function(){};function doInterpret(code,input,cb){var workerCode=interpret.toString()+";function stdout(s){ self.postMessage( {'type': 'out', 'content': s} ); }"+" function stderr(s){ self.postMessage( {'type': 'err', 'content': s} ); }"+" function kill(){ self.close(); }"+" self.addEventListener('message', function(msg){ interpret(msg.data.code, msg.data.input); });";var interpreter=new Worker(URL.createObjectURL(new Blob([workerCode])));interpreter.addEventListener("message",function(msg){cb(msg.data)});interpreter.postMessage({"code":code,"input":input});setTimeout(function(){interpreter.terminate()},1E4)}setTimeout(function(){getOriginalCode();textbox.addEventListener("input",onTextboxChange);testbtn.addEventListener("click",onTestBtn);resetbtn.addEventListener("click",onResetBtn);setTextbox(getOriginalCode())},100);function interpret(code,input){_=undefined;window={};alert=function(s){stdout(s)};window.alert=alert;console.log=alert;prompt=function(s){if(input.length<1)stderr("not enough input");else{var nextInput=input[0];input=input.slice(1);return nextInput.toString()}};window.prompt=prompt;(function(){try{_=undefined;eval(code);if(typeof evalResult=="disabled_function_evaluation"){var callResult=evalResult.apply(this,input);if(typeof callResult!="undefined")stdout(callResult)}}catch(e){stderr(e.message)}})()};</script>

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!

jrich
fuente
ah bien, whoops: |
Downgoat
44
Usar en thislugar de window.
Mama Fun Roll
3
+1 por incluir el significado de la vida en su código fuente
Cyoce