99 (pronunciado "noventa y nueve") es un nuevo lenguaje de programación esotérico (que no debe confundirse con 99 , tenga en cuenta las cursivas). Su tarea en este desafío es escribir un intérprete para 99 que sea lo más breve posible. El envío con la menor cantidad de bytes gana. Tiebreaker va a la presentación publicada primero.
Dado que esta pregunta es un poco más profunda de lo habitual, y estoy ansioso por ver buenas respuestas, otorgaré una recompensa de 250 repeticiones a mi respuesta favorita (no necesariamente el ganador).
99 Especificaciones
99 es un lenguaje imperativo . Cada línea en un programa 99 es una declaración única , y durante la ejecución, el puntero de instrucción comienza en la línea superior y pasa por cada una de las líneas posteriores en orden, ejecutándolas en el camino. El programa finaliza cuando se ejecuta la última línea. Las instrucciones Goto pueden redirigir la ruta del puntero de instrucción.
Newline, space y 9
son los únicos tres caracteres que importan en un programa 99 . Todos los demás personajes son completamente ignorados. Además, los espacios finales en cada línea se ignoran y se leen múltiples espacios seguidos como un solo espacio. ("Nueva línea" se refiere a cualquier codificación de salto de línea común . No importa cuál use su intérprete).
Entonces este programa:
9 BLAH 99 9a9bb9c9
9 this line and the next have 6 trailing spaces 9
Es idéntico a este programa:
9 99 9999
9 9
Variables
Todas las variables en 99 tienen nombres que son uno o más 9
encadenados ( 9+
en expresiones regulares). Por ejemplo, 9
, 99
, y 9999999999
son todas las variables distintas. Naturalmente, hay infinitos (salvo limitaciones de memoria).
El valor de cada variable es un entero de precisión arbitrario con signo. Por defecto, cada variable se asigna a su propia representación numérica. Entonces, a menos que haya sido reasignado, el valor de la variable 9
es el número 9, y el valor de la variable 99
es el número 99, y así sucesivamente. Se podría considerar que trata las variables como números simples hasta que se asignan explícitamente.
Usaré V
para referirme a un nombre de variable arbitrario a continuación.
Cada instancia de V
podría ser reemplazado con 9
, 99
, 999
, 9999
, etc.
Declaraciones
Hay cinco tipos de declaraciones diferentes en 99 . Cada línea en un programa 99 contiene exactamente una declaración.
La sintaxis descrita aquí supone que todos los caracteres extraños se han eliminado, todos los espacios finales se han eliminado y todas las secuencias de espacios múltiples se han reemplazado por espacios individuales.
1. Sin operación
Una línea vacía es un no-op . No hace nada (además de incrementar el puntero de instrucción).
2. Salida
V
Una sola variable V
en una línea imprime esa variable en stdout.
Si V
tiene un número impar de 9
's ( 9
, 999
, etc.), entonces el valor entero de V
dividido por 9 será impreso (en decimal).
Si V
tiene un número par de 9
's ( 99
, 9999
, etc.) entonces el ASCII carácter con código V
dividido por 9, mod 128 será impreso. (Es decir (V / 9) % 128
, un valor de 0 a 127.)
Ejemplo : el programa
9
9999
imprimiría 1W
. La primera línea se imprime 1
porque 9/9 es 1. La segunda línea se imprime W
porque 9999/9 es 1111, y 1111 mod 128 es 87, y 87 es el código de caracteres para W
.
Tenga en cuenta que los saltos de línea no se imprimen entre los tokens de salida. \n
debe imprimirse explícitamente para un salto de línea.
3. Entrada
V
Una sola variable V
en una línea con un espacio inicial toma la entrada de stdin y la almacena en esa variable.
Si V
tiene un número impar de 9
's, entonces el usuario puede escribir cualquier número entero con signo, y V
se establecerá en 9 veces ese valor.
Si V
tiene un número par de 9
's, entonces el usuario puede escribir cualquier carácter ASCII, y V
se establecerá en 9 veces su código de caracteres.
Ejemplo : dado -57
y A
como entrada, este programa
9
9
99
99
haría de salida -57A
. Internamente, la variable 9
tendría el valor -513 y 99
tendría el valor 585.
Su intérprete puede suponer que las entradas son siempre sintácticamente válidas.
4. Asignación
Esta declaración puede ser arbitrariamente larga. Son dos o más variables en una línea, separadas por espacios:
V1 V2 V3 V4 V5 ...
Esto se asigna a la suma de todos los 's con índices pares, menos la suma de los ' s con índices impares (excluyendo ). Las asignaciones son por valor, no por referencia.V1
V
V
V1
Se podría traducir en la mayoría de los idiomas como .V1 = V2 - V3 + V4 - V5 + ...
Entonces, si solo hay dos variables, es una asignación normal:
V1 V2
→ V1 = V2
Si hay tres, entonces es resta:
V1 V2 V3
→ V1 = V2 - V3
Y el signo +
/ -
sigue cambiando de un lado a otro con cada variable adicional:
V1 V2 V3 V4
→ V1 = V2 - V3 + V4
Ejemplo : este programa generaría 1110123
:
999 Prints triple-nine divided by nine (111).
999 9 9 Assigns triple-nine to zero (nine minus nine).
999 Prints triple-nine divided by nine (0)
9 999 9 Assigns single-nine to negative nine (zero minus nine).
999 999 9 Adds nine to triple-nine (really subtracts negative nine).
999 Prints triple-nine divided by nine (1).
999 999 9 Adds nine to triple-nine (really subtracts negative nine).
999 Prints triple-nine divided by nine (2).
999 999 9 Adds nine to triple-nine (really subtracts negative nine).
999 Prints triple-nine divided by nine (3).
5. Ir a (saltar si todo es cero)
Esta declaración también puede ser arbitrariamente larga. Son dos o más variables en una línea, separadas por espacios, con un espacio inicial :
V1 V2 V3 V4 V5 ...
Si algunos de los valores además no son cero, entonces esto se comporta como un no-op. El puntero de instrucciones se mueve a la siguiente línea como de costumbre.V1
Si todos los valores además son cero, entonces el puntero de instrucción se mueve al número de línea . Las líneas están indexadas a cero, por lo que si es cero, el puntero se mueve a la línea superior. El programa finaliza (normalmente, sin error) si es negativo o es mayor que el índice más alto posible (número de líneas menos uno).V1
V1
V1
V1
Tenga en cuenta que no se dividió por 9 aquí. Y dado que es imposible que una variable sea un valor que no sea múltiplo de 9, solo se puede saltar a los números de línea que son múltiplos de 9.V1
Ejemplos:
Este programa imprimirá 1
para siempre:
9 Prints single-nine divided by nine (always 1).
99 9 9 Assigns double-nine to zero.
99 99 Jumps to line zero (top line) if double-nine is zero.
Este programa
99999999 Print G.
999 99 Set triple-nine to ninety-nine.
9999999999 9999999999 9999999999 99 99 9 9 999 999 Set 10-nine to zero.
99999999999 9999999999 Set 11-nine to zero.
999 Print triple-nine's value divided by nine. (This is the ninth line.)
99999999 Print G.
999 999 9 Subtract nine from triple-nine.
99999 999 Jump to line 5-nines if triple-nine is zero (ends program).
9 99999999999 9999999999 Jump to line nine if 10-nine and 11-nine are zero (always jumps).
mostrará los números del 11 al 1, en orden decreciente, rodeados por G
's:
G11G10G9G8G7G6G5G4G3G2G1G
Detalles adicionales
El intérprete ideal se ejecutará desde la línea de comandos con el nombre del archivo del programa 99 como argumento. La E / S también se realizará sobre la marcha en la línea de comando.
Sin embargo, puede escribir una función de intérprete que tome el programa como una cadena, así como una lista de los tokens de entrada (por ejemplo ["-57", "A"]
). La función debe imprimir o devolver la cadena de salida.
Formas ligeramente diferentes de ejecutar el intérprete y manejar la E / S están bien si estas opciones son imposibles en su idioma.
Bonificación: escriba algo genial en 99 y con gusto lo pondré en esta publicación como ejemplo.
- Aquí hay un Pastebin de un lindo programa "99 Botellas de cerveza" de la respuesta de Mac .
¡Espero que hayas disfrutado de mi 99º desafío! :RE
fuente
Respuestas:
CJam, 157 bytes
Pruébalo en línea:
Explicación
Intentar formatear esto con la sangría adecuada y los comentarios probablemente tomaría una eternidad, por lo que solo daré un resumen algorítmico.
El código es un bloque, las funciones análogas a anónimas de CJam. El bloque espera la cadena del programa y la lista de entradas en la pila cuando se ejecuta.
La inicialización consta de tres pasos. Primero, se guarda la lista de entrada. Luego, se eliminan todos los caracteres del programa que no tienen sentido y el resultado se divide en una lista de líneas y se guarda. Finalmente, se inicializa la lista de variables. Esta lista asigna cada variable, indexada por la longitud del nombre, a su valor dividido entre 9 (una variable nunca puede contener un valor que no sea un múltiplo de 9, y todas las operaciones excepto goto se benefician de este cambio). La lista se inicializa hasta la longitud de la línea más larga, que es un límite superior en el nombre varaible más largo presente. También hay un poco de inicialización implícita debido a los valores de las variables iniciales: el número de línea es 0 y el índice de entrada es -1.
El intérprete se implementa como cabría esperar: un bucle que lee la siguiente línea, incrementa el número de línea y ejecuta la línea mientras el número de línea apunta a una línea existente. El análisis de líneas primero verifica que la línea no esté vacía, luego las ramas en función de si el arity es 1 o> 1, luego las ramas en función de si había un espacio inicial. Estas cuatro ramas emulan las cuatro operaciones (excluyendo no-op) de una manera principalmente directa, aunque de forma agresiva como cualquier otra cosa. Quizás una optimización de la nota es que, dado que una secuencia de entrada válida siempre debe producir un elemento de tipo esperado por el programa, omití hacer casos separados para la entrada en función de la longitud del nombre de la variable. Simplemente se supone que el elemento leído de la lista de entrada es del tipo esperado.
fuente
128%
con128,=
.Python 3,
421414410404388395401 bytesGolfizado:
Sin golf:
Prácticamente solo una implementación literal de la especificación, desarrollada hasta donde puedo obtenerla.
Ejecute desde la línea de comando proporcionando un archivo de código fuente 99 como único argumento (por ejemplo, el último ejemplo del OP):
Como beneficio adicional, aquí hay una implementación (bastante pobre) de "99 botellas" en 99 : http://pastebin.com/nczmzkFs
fuente
else
después de que se pudiera eliminar un número, pero cuando lo intenté antes recibí un error de sintaxis. ¡Tus otros consejos son muy apreciados!goto
rutina y al obtener el valor predeterminado de la variable). En lo que respecta a un usuario del idioma, no hay diferencia.else
sí mismo, solo el espacio anterior. Por ej3*n+1if n%2else n//2
.else
. Por ejemplo, he intentado reemplazarprint(w if L(e)%2 else chr(w%128))
conprint(w if L(e)%2else chr(w%128))
y obtuve una excepción de sintaxis.e
oE
, y (de los comentarios) no para0or
ninguno.Lisp común,
1180857837836 bytesSé que esto no va a ganar, pero me divertí jugando al golf. Logré eliminar 343 bytes, que son más de dos 99 intérpretes escritos en CJam.
Además, de manera bastante divertida, cuanto más intento comprimirlo, más me convencen de que para Common Lisp, es más corto compilar el código que intentar interpretarlo sobre la marcha.
Hay un solo
tagbody
para realizar 2 bucles:las variables locales se declaran en
&aux
Ungolfed, comentó
Usamos entrada / salida estándar durante la evaluación, lo que significa que usamos estándar
read
yprinc
funciones. Por lo tanto, el código resultante puede hacerse ejecutable en la línea de comandos, como se muestra a continuación.Las entradas no se desinfectan completamente cuando se ejecutan 99 programas: se supone que el usuario sabe qué tipo de valores se esperan.
El único tiempo de ejecución posible sobrecarga de de puede ocurrir al saltar, ya que debemos evaluar el valor de una variable y hacer coincidir ese valor con una etiqueta. Excepto que, el intérprete será bastante eficiente.
Basado en la observación inteligente de Mac que no necesitamos dividir y multiplicar por 9 cada vez, la versión actual se las arregla para nunca dividir ni multiplicar por 9 durante la ejecución.
Ejemplo
Si reemplazamos
defmacro
pordefun
, vemos el código generado. Por ejemplo:Aquí está el código resultante:
Cuando se ejecuta, imprime "G11G10G9G8G7G6G5G4G3G2G1G"
Línea de comando
Podemos construir un ejecutable volcando un núcleo y especificando la
toplevel
función. Defina un archivo llamadoboot.lisp
donde coloca eldefmacro
, y luego escriba lo siguiente:Correr
sbcl --load boot.lisp
da el siguiente resultado:Luego, ejecutando el programa compilado 99 :
99 botellas
Si está interesado, aquí está el código compilado para el programa de 99 botellas escrito en la respuesta de Mac : http://pastebin.com/ZXe839CZ (esta es la versión anterior donde tenemos
jmp
yend
etiquetas, una lambda circundante y una aritmética más bonita).Aquí hay una ejecución con la nueva versión, para demostrar que aún funciona: http://pastebin.com/raw.php?i=h73q58FN
fuente
TI-84 básico (Simulador de escritura),
376373377381 bytesSi se ejecuta en una calculadora TI-84, podrá usarla en una prueba estandarizada ... así que es útil;)
Versión mínima del sistema operativo: 2.53MP (MathPrint) debido a la suma sigma
Las directrices PS ASCII no se pudieron seguir exactamente, pero en TI-Basic
:
es una nueva línea. Por lo tanto, todas las nuevas líneas reales en el código significan que no se requiere el:
o#
al comienzo de cada línea. Los tokens iniciales:
y#
solo diferencian entre comentarios y código.Volcado hexadecimal original (376 bytes)
Edición n. ° 1 : 3 bytes optimizados mediante la observación de Mac. Ediciones n. ° 2 y n. ° 3 : errores corregidos detectados por Runer112.
fuente
#
, para los comentarios? (Nota: Los comentarios en el código real se implementan como una línea única con una cadena sin cerrar, que clobbers Ans)Ans
entrada se sobrescribe, por lo queAns->Str0
en la línea 6 se producirá un error, hay varias instancias en las que el argumento de longitud de unsub()
comando puede ser cero, lo que resulta en un error,Ans
en la línea 11 será una cadena también loAns-J
hará el error ... Y solo miré aproximadamente la primera mitad del programa.sub()
comando puede tener longitud cero y arrojar un error. Y una vez quesub()
se solucionan las invocaciones, me temo que puede revelar más problemas.9
es el número 9, y el valor de la variable99
es el número 99, y así." Y las cadenas de longitud 0 pueden producirse por medios como""
, pero es una especie de error que básicamente ningún comando de manipulación de cadenas puede consumir o producir una cadena vacía, incluidasub()
.C 426
458 481 497Editar Tal vez estoy yendo demasiado lejos, pero esto funciona con Visual C: eliminó stdio.h, usando int en lugar de FILE * para fopen y getc
Editar 2 Reordenar paso de ejecución, más desorden, 32 caracteres guardados
Programa de consola independiente, nombre del programa tomado en la línea de comando y entrada / salida a través de la consola.
Estilo antiguo K&R, tipo predeterminado int para variables y parámetros globales. Asumiendo EOF definido como -1 (como lo estoy en cada implementación de C que conozco)
Compila con advertencias con Visual Studio 2010 (proyecto Win32 consola C ++, compila como C) Compila en Ideone, pero no puede ejecutarse ya que necesita un archivo.
Primer paso, el código fuente se lee y analiza, cada línea se almacena como una secuencia de enteros basada en los números de 9s. Si hay un espacio en blanco inicial, el primer número es negativo. Entonces:
9 BLAH 99 9a9bb9c9
(9 99 9999
) se convierte en-1,2,4
Hay un acceso directo, no tan legal: todos los códigos ascii menores que '' se consideran líneas nuevas.En este paso, todas las variables utilizadas se preinicializan.
El paso de ejecución sigue las especificaciones, sin lujos, guarda los números de almacenamiento divididos por 9.
Mismo código más legible (espero), espacios y líneas nuevas añadidas
fuente
Haskell, 550 bytes
Ejemplo ejecutado con el programa "cuenta regresiva" almacenado en el archivo
i.99
Versión sin golf:
fuente
JavaScript (ES6) 340
352Una función con 2 parámetros.
El tercer parámetro opcional (predeterminado 10k) es el número máximo de iteraciones: no me gusta un programa que se ejecute para siempre
JSFiddle para probar
fuente
q / k,
490469.
El script es una mezcla de q y k, así que primero defino algunas palabras clave q que quiero usar varias veces en k funciones. (básicamente #define macros)
f
lee el archivo pasado al programa y elimina los caracteres innecesariosm
toma una lista / vector y multiplica los índices impares por -1b
es solo una función vacía, utilizada para las líneas no operativasp
Es la función de impresión.K
es una función que examina una variable. Si la variable existe, la devuelve, de lo contrario solo devuelve el literal.v
es la función de asignacióng
es la función goto.r
toma una cadena y decide qué operación debe aplicarse.Y finalmente, solo itero a través de la
f
lista de cadenas,n
como iterador. La función goto se actualizarán
según sea necesario.fuente
Perl,
273 266 255 244238Saltos de línea añadidos para mayor claridad.
Nombre del programa tomado en la línea de comando:
Cada línea del programa se convierte en código Perl, por ejemplo:
Más detalles
fuente