$p=$a[$p]+=$_ for@F;redo
Pruébalo en línea! (contiene un encabezado que imprime el estado interno y se detiene después de 10 iteraciones, para que el comportamiento sea observable)
Sobre el idioma
He pasado los últimos días trabajando en la máquina I / D , una de mis últimas ideas para lenguajes de programación muy simples. Funciona de la siguiente manera: el almacenamiento de datos consiste en una RAM sin límites, inicialmente todos ceros. Cada elemento puede almacenar un número entero ilimitado (aunque en la práctica, la mayoría de los programas de máquina de I / D solo almacenarán números enteros pequeños en la mayoría de ellos, y utilizarán los números enteros ilimitados solo como una forma de direccionar celdas con direcciones grandes). También hay un puntero de datos, que apunta a una celda (es decir, contiene la dirección como una celda); Inicialmente también es cero.
Solo hay dos comandos:
I
: Incremente la celda a la que apunta el puntero de datos. (El puntero de datos en sí permanece sin cambios).
D
: Haga referencia al puntero de datos, es decir, lea el valor de la celda a la que apunta el puntero de datos. Luego almacene el valor resultante que leyó en el puntero de datos.
La ejecución simplemente ejecuta el programa en un ciclo repetidamente, para siempre.
Es bastante sorprendente que un lenguaje así de simple sea completo de Turing, así que he estado trabajando para demostrarlo. Aquí está la prueba . Es bastante similar (pero más simple que) la prueba para Three Star Programmer, un lenguaje muy similar (y de hecho, esta presentación utiliza el mismo "shell" básico de OISC alrededor del programa, que difiere solo en la instrucción real implementada).
Sobre el programa
Uso
La entrada debe darse en la entrada estándar, y es un programa de máquina I / D sin comentarios, y usando la sintaxis RLE / OISC. (La máquina I / D tiene dos sintaxis equivalentes diferentes, pero para el golf, este programa solo admite uno de ellos). En esta sintaxis, un programa es una secuencia de números en decimal, que representa la longitud de las ejecuciones de I
comandos entre D
comandos. (Puede especificar dos o más D
comandos consecutivos colocando una "ejecución de 0 I
comandos" entre ellos, por lo que la sintaxis es completamente general).
Explicación
Como se puede ver en el programa, esto no está implementando los comandos I
y D
individualmente. De hecho, es un intérprete optimizador (muy levemente) (simplemente porque es más corto para escribir de esta manera). La clave es ver que una serie de comandos de incremento n incrementen el objetivo del puntero de datos n veces, es decir, agreguen n ; y una ejecución de comandos de incremento 0 también se puede implementar de esta manera, ya que agregar 0 a la memoria no tiene ningún efecto. Entonces, la operación que implementamos realmente es alternar entre implementar una serie de I
s y una D
. O en otras palabras, "agregue nal valor señalado por el puntero de datos (almacenándolo de nuevo en el valor señalado por el puntero de datos), luego lea el valor señalado por el puntero de datos y guárdelo en el puntero de datos ". Eso es claramente más detallado de lo que necesita ser, y podemos simplificar aún más esto para "agregar n al valor señalado por el puntero de datos, luego almacenar ese valor tanto en el objetivo del puntero de datos como en el puntero de datos en sí".
Eso hace que sea el núcleo de nuestro programa. Estamos usando una matriz $a
para almacenar la RAM, y $p
como puntero de datos (indexación en la matriz):
$p=$a[$p]+=$_
+ $_ add {the run length}
$a[$p] to the element of $a pointed to by $p
$a[$p] = storing the result back into that element
$p= and also in the pointer itself
Convenientemente, Perl interpreta los elementos de la matriz no inicializados como 0 cuando se tratan como números, por lo que la matriz se inicializará perezosamente en ceros para nosotros sin ningún código explícito para eso. (Un problema potencial es la precisión numérica cuando los números aumentan; sin embargo, eso solo sucederá si la cantidad de la matriz que se usa excede el espacio de direcciones de la máquina (los enteros Perl son lo suficientemente grandes como para contener punteros), algo que no puede suceder en una máquina idealizada)
Finalmente, todo lo que necesitamos hacer es colocar este programa en un par de bucles. El for@F
bucle, combinado con la -a
opción de línea de comando, recorrerá los campos de entrada estándar (la definición predeterminada de "campo" aquí se dividirá en espacios en blanco). El redo
bucle colocará todo el programa en un bucle implícito (que no sea, convenientemente, la lectura de la entrada estándar), lo que hará que el programa se ejecute en un bucle repetidamente, como lo requiere la semántica de la máquina I / D.
eval
soluciones triviales .