¡Quine entrópico!


12

Su tarea es escribir un programa o función que:

  • Cuando se ejecuta por primera vez, genera su código fuente.
  • En ejecuciones posteriores, debería generar lo que emitió anteriormente, pero con un cambio de carácter aleatorio (definido a continuación). No tiene que ser un cambio aleatorio uniforme, pero cada cambio posible debe tener una probabilidad distinta de cero.

    Después de la primera ejecución, su programa ya no será necesariamente una quine; la salida habrá cambiado (y el programa también es libre de modificarse).

Por ejemplo, si su quine era ABCD, ejecutarlo repetidamente podría imprimir:

ABCD
A!CD
j!CD
j!CjD

Especificaciones

  • Un cambio de personaje es:

    • La inserción de un carácter aleatorio,
    • La eliminación de un carácter aleatorio, o
    • Un reemplazo de un personaje con un nuevo personaje aleatorio. Tenga en cuenta que se permite que el nuevo personaje sea el mismo que reemplaza, en cuyo caso no se realizará ningún cambio.

    Por supuesto, eliminar o reemplazar un carácter de una cadena vacía no es un cambio válido.

  • A pesar de que esto se etiqueta como , las reglas contra la lectura de su código fuente no se aplican.

Puede usar cualquier conjunto de caracteres siempre que incluya los caracteres utilizados en su código fuente.


1
¿A qué personajes se refiere cada personaje ?
Dennis

2
¿Con qué frecuencia tiene que funcionar esto? Claramente, no puede ser arbitrariamente frecuente o de lo contrario, todos los programas posibles pueden ser más largos o más largos que el original para ser una solución al desafío.
Martin Ender

1
¿Se puede agregar el personaje en cualquier lugar, o solo al final?
Conor O'Brien el

1
@ ConorO'Brien Anywhere.
Esolanging Fruit

1
¿Cuántas iteraciones tiene que funcionar?
dylnan

Respuestas:


7

Python 3 , 288 270 224 212 195 196 194 180 178 168 bytes

f=__file__
m=open(f).read()
x=m	
print(end=x)
h=hash
k=h(f)
n=k%2
a=h(m)%-~len(x)
x=x[:a]+(not(k%3)*x)*chr(k%127)+x[a+n:]
open(f,'w').write(m.replace("\t",";x=%r\t"%x))

Pruébalo en línea!

Después de imprimir el código fuente del archivo en la primera iteración, agregamos una línea adicional para establecer x en el nuevo código fuente, en lugar de m.

Explicación:

f=__file__    #Open and read the source code
m=open(f).read()

x=m       #Set x to the source code for the first iteration
x="..."
...
x="..."   #Set x to the latest iteration
          #On the last iteration there's a tab character to mark progress
print(end=x)    #Print the previous iteration's text

#Modify the text
h=hash
k=h(f)            #Generate a random number to use
n=k%2             #Whether the character will be inserted or changed/deleted
a=h(m)%-~len(x) #The index of the change
                         #Add 1 to the range to append new characters, and to avoid mod by 0 in the case of an empty string
x=x[:a]+(not(k%3)*x)*chr(k%127)+x[a+n:]    #Make the change

open(f,'w').write(m.replace("\t",";x=%r\t"%x))   #Modify the source code, adding the new iteration of the source code

Suponiendo que hashdevuelve un número aleatorio uniforme, hay aproximadamente 1/6 de posibilidades de insertar un nuevo personaje, 1/6 de posibilidades de cambiar un carácter existente y 2/6 de posibilidades de eliminar un carácter. ¿Cuál es la probabilidad de 2/6 restante que preguntas? ¡Por qué no hace nada 2/6 del tiempo!

(Aquí hay un programa de validación adaptado de las respuestas de mbomb007 . ¡ Pruébelo en línea! )


Creo f=__file__que también ayudaría en el primer paso.
Ørjan Johansen

4

Python 3 , 205 195 bytes

s='print(end=x);h=hash;k=h(x);n=k%2;a=h(s)%-~len(x);x=x[:a]+(not(k%3)*x)*chr(k%127)+x[a+n:];open(__file__,"w").write("s=%r;x=%r;exec(s)"%(s,x))';x='s=%r;x=%r;x=x%%(s,x);exec(s)';x=x%(s,x);exec(s)

Pruébalo en línea!

Quería probar una versión que no lea el código fuente. Resultó que no era malo como pensaba, y solo está a unos 30 bytes detrás de la versión que lo hace . La explicación de cómo funciona es principalmente la misma que la otra respuesta, pero inicializa x de manera diferente ya que no puede leer el código fuente.


4

Python 2 , 779 801 bytes

Aunque el desafío se editó para mostrar que la lectura de su fuente está permitida, ya estaba creando mi solución sin eso. Entonces, para demostrar que es posible, lo terminé. Sin lectura del archivo fuente:

s='s=%r;print s%%s\nfrom random import*;L=4;f=open(__file__,"wa"[L>5]);R=randint\nf.write("\\n".join((s%%s).split("\\n")[1:5:2]).replace("4",`map(ord,s%%s)`))\nif L>5:exec\'b=[];h=%%d\\nwhile~-h:b+=[h%%%%1000];h/=1000\\nwhile b:r,p,n=b[-3:];b=b[:-3];L=[L[:p]+L[p+1:],L[:p]+[r]+L[p+n:]][n<2if L else 1]\\nprint"".join(map(chr,L))\'%%1\n\nn=R(0,2);p=R(0,len(L if L>5else s%%s));r=R(0,255);f.write("%%03d"*3%%(n,p,r))';print s%s
from random import*;L=4;f=open(__file__,"wa"[L>5]);R=randint
f.write("\n".join((s%s).split("\n")[1:5:2]).replace("4",`map(ord,s%s)`))
if L>5:exec'b=[];h=%d\nwhile~-h:b+=[h%%1000];h/=1000\nwhile b:r,p,n=b[-3:];b=b[:-3];L=[L[:p]+L[p+1:],L[:p]+[r]+L[p+n:]][n<2if L else 1]\nprint"".join(map(chr,L))'%1

n=R(0,2);p=R(0,len(L if L>5else s%s));r=R(0,255);f.write("%03d"*3%(n,p,r))

Pruébalo en línea! (Tenga en cuenta que esto no modificará la fuente. Debe ejecutarlo localmente para que funcione)

Para demostrar que las transformaciones funcionan, aquí es un programa de prueba (actualmente configurada para recoger siempre 100para r, y se imprime el resultado para cada combinación de ny ppara la lista inicial.)



Explicación:

s='s=%r;print s%%s...';print s%s...

La primera línea es su quine clásico, pero mucho más para dar cuenta de lo que viene después.

from random import*;L=4;f=open(__file__,"wa"[L>5]);R=randint

Importar para enteros aleatorios. Lse convertirá en una lista de ordinales del código fuente, pero inicialmente es un número entero que no se usa en ningún otro lugar de la fuente para permitir el reemplazo de una cadena. Abra el archivo para escribir la nueva fuente. En ejecuciones posteriores, se abrirá para agregar en su lugar.

f.write("\n".join((s%s).split("\n")[1:5:2]).replace("4",`map(ord,s%s)`))

Elimina la primera y tercera línea de código. Reemplace lo 4anterior con la lista de ordinales.

if L>5:exec'b=[];h=%d\nwhile~-h:b+=[h%%1000];h/=1000\nwhile b:r,p,n=b[-3:];b=b[:-3];L=[L[:p]+L[p+1:],L[:p]+[r]+L[p+n:]][n<2if L else 1]\nprint"".join(map(chr,L))'%1

n=R(0,2);p=R(0,len(L if L>5else s%s));r=R(0,255);f.write("%03d"*3%(n,p,r))

En pedazos:

  • if L>5:- Omite esta línea en la primera ejecución. Más tarde, Lhabrá una lista, y esto se ejecutará. Explicaré lo execúltimo, porque no se ejecuta la primera vez.

  • n- Un número aleatorio 0-2. Esto determina qué modificación ocurre (0 = insertar, 1 = reemplazar, 2 = eliminar).

  • p - Una posición aleatoria en la lista en la que ocurrirá la modificación.

  • r - Un número aleatorio para insertar o reemplazar en la lista

  • f.write("%03d"*3%(n,p,r))- Agregue los 3 randoms al final del archivo fuente. En cada ejecución, esto se agregará a un número entero que codifica todos los cambios en la fuente inicial que se han producido.

  • exec'b=[];h=%d...'%1...- Obtenga los números aleatorios (que se encuentran después %1en ejecuciones posteriores), aplique los cambios a la lista e imprima.

  • while~-h:b+=[h%%1000];h/=1000- Construya una lista de los randoms generados hasta el momento, teniendo en cuenta el inicio 1, lo que evita problemas con los ceros iniciales.

  • while b:r,p,n=b[-3:];b=b[:-3] - Asignar los randoms para esta iteración.

  • L=[L[:p]+L[p+1:],L[:p]+[r]+L[p+n:]][n<2if L else 1] - (0 = insertar, 1 = reemplazar, 2 = eliminar)

  • print"".join(map(chr,L)) - Imprime la fuente modificada.


¿Esto a veces elimina un carácter inexistente del final de la cadena? Como ppuede ser la longitud de la cadena. Además, ¿cuál es el comportamiento con una cadena vacía?
Jo King

@JoKing agregué un programa de prueba. Todo cambio de personaje posible puede suceder. Simplemente muestra que cada posición puede seleccionarse para insertar, reemplazar o eliminar, y que maneja una lista vacía. tio.run/##LYoxDsMgDEVnOAUjCAZgRO0NuIHloUOaRIocy6JDT08dpdt/…
mbomb007

No creo que ningún cambio sea válido, aunque le pregunté al OP. La pregunta diceOf course, deleting or replacing a character from an empty string is not a valid change
Jo King

Le pregunté a Esolanging Fruit, y dicen que ningún cambio es válido, pero no para una cadena vacía.
Jo King

1
@JoKing debería ser reparado.
mbomb007

1

Java 10, 370 bytes

String s;v->{if(s==null){s="String s;v->{if(s==null){s=%c%s%1$c;s=s.format(s,34,s);}else{int r=s.length();r*=Math.random();char c=127;c*=Math.random();s=s.substring(0,r)+(c%%3<2?c:%1$c%1$c)+s.substring(r+(c%%3>0?1:0));}}";s=s.format(s,34,s);}else{int r=s.length();r*=Math.random();char c=127;c*=Math.random();s=s.substring(0,r)+(c%3<2?c:"")+s.substring(r+(c%3>0?1:0));}}

Pruébalo en línea.

Explicación:

String s;               // Class-level String variable to store the modifying source code
v->{                    // Method without parameter nor return-type
  if(s==null){          //  If this is the first execution of this function:
    s="String s;v->{if(s==null){s=%c%s%1$c;s=s.format(s,34,s);}else{int r=s.length();r*=Math.random();char c=127;c*=Math.random();s=s.substring(0,r)+(c%%3<2?c:%1$c%1$c)+s.substring(r+(c%%3>0?1:0));}}";
                        //   Set `s` to the unformatted source-code
    s=s.format(s,34,s);}//   And then to the formatted source-code
else{                   //  For any following executions of this function:
  int r=s.length();r*=Math.random();
                        //   Random index in range [0, length_of_modified_source_code)
  char c=127;c*=Math.random();
                        //   Random ASCII character in unicode range [0, 127)
  s=                    //   Replace the current String `s` with:
    s.substring(0,r)    //    The first [0, `r`) characters of the modified source code `s`
    +(c%3<2?            //    If the random option is 0 or 1:
           c:"")        //     Append the random character
        +s.substring(r  //    Append the rest of the modified source code `s`, but:
          +(c%3>0?      //     If the random option is 1 or 2:
             1:0));}}   //      Skip the first character of this second part

Explicación general:

-parte:

  • La cadena scontiene el código fuente sin formato.
  • %sse utiliza para ingresar esta cadena en sí misma con el s.format(...).
  • %c, %1$cy 34se usan para formatear las comillas dobles.
  • ( %%se usa para formatear el módulo %).
  • s.format(s,34,s) lo pone todo junto

Aquí un programa básico de Java Quine.

Parte del desafío:

  • String s; es el código fuente que modificaremos a nivel de clase.
  • int r=s.length();r*=Math.random();se usa para seleccionar un índice aleatorio del código fuente en el rango [0, length_of_modified_source_code).
  • char c=127;c*=Math.random();se utiliza para seleccionar un carácter ASCII aleatorio (incluidos los no imprimibles) en el rango unicode [0, 126].
  • c%3se usa para seleccionar una opción aleatoria de 0, 1 o 2. La opción 0 agregará el carácter aleatorio antes del índice r; la opción 1 reemplazará el carácter en el índice rcon el carácter aleatorio; y la opción 2 eliminará el carácter en el índice r.
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.