Todos hemos visto esos "hax de matemáticas" en línea que se ven así:
Think of a number, divide by 2, multiply by 0, add 8.
Y, por arte de magia, ¡todos terminan con el número 8!
Idioma
Definamos un lenguaje de programación que use la sintaxis del texto anterior, llamado "WordMath". Los scripts de WordMath siguen esta plantilla:
Think of a number, <commandlist>.
Lo que básicamente significa: tomar un número (como entrada de STDIN) como acumulador inicial, ejecutar todos los comandos y generar el resultado.
Los comandos están separados por el delimitador ,
(coma + espacio). Los comandos válidos son (nota que #
representa un número entero no negativo :) :
add #
/subtract #
- Suma / resta el valor del acumulador.divide by #
/multiply by #
- floordiv / multiplica el acumulador por el valor dado.subtract from #
- Similar asubtract
, pero lo hace enacc = # - acc
lugar deacc = acc - #
repeat
- Haz el último comando de nuevo. Este no puede ser el primer comando, pero debe admitir múltiples repeticiones consecutivas.
El reto
Su tarea es crear un programa o función que tome un script válido de WordMath como entrada y lo transforme en un programa completo válido, en el mismo idioma en que se encuentra su código.
Por ejemplo, si mi código está en Python 2 y el script es:
Think of a number, subtract from 10, add 10, multiply by 2.
El programa generado puede ser:
a = input()
a = 10 - a
a += 10
a *= 2
print(a)
O alternativamente:
print(((10-input())+10)*2)
Siempre que se trate de un programa completo que toma información STDIN
e imprime a STDOUT
, o los equivalentes más cercanos del idioma.
Reglas
- Su programa original puede suponer que la entrada siempre es un script válido de WordMath.
- Los programas transpilados no tienen que manejar errores matemáticos como la división por 0.
- Los programas transpilados pueden suponer que la entrada representa un entero con signo válido, dentro del rango de enteros estándar de su idioma.
- Este es el código de golf , por lo que gana la solución más corta (en bytes).
- Solo importa el recuento de bytes de su programa original: ¡el código generado puede ser todo el tiempo que desee!
Guiones de ejemplo
Ejemplo 1:
Think of a number.
Tome información, no haga nada, muéstrela: el programa cat de WordMath.
Ejemplo 2
Think of a number, divide by 5, subtract from 9.
Recuerde que "dividir" es la división de piso, así que para este programa 6 -> 8
, y 29 -> 4
.
Ejemplo 3
Think of a number, add 5, add 10, multiply by 2, subtract 15, repeat, divide by 2.
¡El programa extendido de gatos!
Ejemplo 4
Think of a number, subtract 1, repeat, repeat.
Toma un número y resta 3.
-5/3
? ¿Redondeamos hacia0
o hacia el infinito negativo?Respuestas:
05AB1E ,
59565452 bytesPruébalo en línea!
Mi cerebro duele como el infierno después de eso ... Sale en código 05AB1E de la siguiente manera:
Think of a Number
se elimina debido a la entrada implícita.Subtract From #
coberteras a#s-
(de intercambioa
yb
y operación realizan).Subtract #
convierte a#-
.Add #
convierte a#+
.Multiply by #
convierte a#*
.Divide by #
convierte a#/
.Repeat
toma lo que se almacenó por última vez en el registro y lo concatena.Explicado:
Ejemplo:
Entrada:
Salida:
Pruebe la solución con una entrada de 10:
Pruébalo en línea!
Véalo en google:
Aquí hay un enlace a la misma ecuación escrita en google.
fuente
Preprocesador C, 362 bytes
Casi lo tengo funcionando SOLO en el preprocesador C, pero el comando de repetición resulta ser demasiado difícil de implementar. Entonces, en su lugar, utilicé el preprocesador para convertir la entrada en una matriz que luego es interpretada por algún código adicional.
La entrada debe proporcionarse en "input.wm" o simplemente volcar en la fuente en esa línea. Incluí sus bytes en mi recuento porque creo que es un poco hacky y ligeramente en contra de las reglas del desafío, por lo que es apropiado.
De todos modos, una vez que descargue su fuente de WordMath en input.wm donde un compilador pueda encontrarla, debería poder compilar esto, tal cual, con advertencias para producir un ejecutable que haga lo que dice la fuente de WordMath.
fuente
Retina, 170 bytes
¿Porque quién no querría ver esto?
Pensé en lo maravilloso que sería ver una solución Retina, y decidí crearla rápidamente. Solo tomó una hora. Como de costumbre, el recuento de bytes asume la codificación ISO 8859-1.
Pruébalo en línea
La salida tiene una nueva línea final que no debe copiarse al probar el programa resultante. El programa no admite negativos, porque el rango entero estándar de Retina (en unario) no.
Explicación:
Programas de matemáticas:
Añadir:
Agregue el número de unos al principio. Añadir 5:
Sustraer:
Eliminar el número de unos desde el principio. Restar 5:
Restar de:
Reemplace la entrada
1
s conx
s. Poner al lado del número fijo. Retirar repetidamentex1
. Restar de 10:Multiplicar por:
Reemplace cada uno
1
con un cierto número de ellos. Multiplicar por 3:Dividido por:
Esto usa mi programa Retina para la División de enteros . Dividir por 2:
fuente
$
coincide al final de la cadena o frente a un salto de línea final. Lo necesitas\z
si solo quieres lo primero.GNU awk, 139 bytes
Invocación:
Casos de prueba:
fuente
Haskell,
232231 bytesPor supuesto, un programador funcional preferiría devolver una función en lugar de una cadena que representa un programa, pero aquí vamos:
Observaciones: siempre comenzamos agregando cero, de lo contrario la transpilación del trivial programa WordMath no daría suficiente información para inferir el tipo en el que
read
se utiliza.subtract from n
podría implementarse como(n-)
, pero lo uso((-)n)
para mayor uniformidad. En el caso desubtract n
que copie elsubtract
de la entrada para no tener que escribirlo, pero necesito compensar el espacio que falta al final.repeat
se usa como operación predeterminada; junto con una operación previa inicial vacía, esto permite ignorar fácilmente las primeras cuatro palabras.Ejemplo de uso:
Los otros ejemplos dan los siguientes resultados:
fuente
h
podría parecer algo asíh s n r|x<-s.read.init$n=x%r.x
y llamarse con el primer argumento una función comoh(+)n r
(y debe haber algunaflip
en algún lugar para obtener el orden correcto del operador), el caso base es_%_=id
. La función principal puede evitar todas las repeticiones y simplemente sert l=id%words l
. - Gracias al curry, podría verse como un intérprete, y esa idea podría conducir a una solución más fácil y / o más corta.Python 2,
263258260221 bytesEsto probablemente aún podría ser mucho más corto.
Pruébalo en línea
Yo uso en
//
lugar de/
, porque la última instrucción tendrá un.
al final, haciendo que cualquier número sea flotante. Entonces, para mantener la división consistente, utilizo la división entera.Salida de casos de prueba:
fuente
if
s poro
lo siguiente (que creo que debería funcionar):o=[[o+[['+-'['s'in c],'//']['v'in c],'*']['m'in c]+n,n+'-'+o]['f'in c],'input()']['T'in c]
puede bajarlo a 224.Befunge,
342305bytesPruébalo en línea!
Salida
El código que genera comienza con un
&
comando (valor de entrada) y termina con los comandos.
(valor de salida) y@
(salir). En el medio tenemos los diversos cálculos en el formulario<number><operation>
, donde la operación puede ser+
(sumar),-
(restar),/
(dividir por),*
(multiplicar por) y\-
(restar de).El número en sí es un poco complicado, porque Befunge solo admite literales numéricos en el rango de 0 a 9, por lo que cualquier cosa mayor que eso debe calcularse manualmente. Como ya estamos leyendo los números en caracteres por caracteres, simplemente acumulamos el número a medida que se lee cada dígito, por ejemplo, 123 se convierte
155+*2+55+*3+
, es decir(((1 * 10) + 2) * 10) + 3
.Ejemplos
Explicación
Befunge no tiene la capacidad de manipular cadenas como tal, por lo que la mayor parte del análisis se maneja contando caracteres. Comenzamos simplemente omitiendo los primeros 18 caracteres, lo que nos lleva más allá de pensar en una frase numérica (más una coma o punto). Luego, si el siguiente carácter es alguna forma de nueva línea o EOF, vamos directamente a la rutina de salida, de lo contrario, continuamos buscando una lista de comandos.
Para analizar un comando, seguimos contando caracteres hasta llegar a un dígito o separador. Si es un separador, debe haber sido el comando de repetición que manejamos como un caso especial. Si es un dígito, lo agregamos a nuestro búfer de salida y continuamos buscando más dígitos. Cada vez que se genera un dígito, lo anteponemos con
55+*
(para multiplicar el total hasta ahora por 10) y lo+
agregamos con (para agregarlo al total). Una vez que los dígitos están terminados, agregamos el carácter de comando.En cuanto a cómo se determina el comando, tomamos el recuento de caracteres hasta el primer dígito módulo 7. Para sumar esto es 4 (incluido el siguiente espacio), para restar es 2, para dividir por 3, para multiplicar por 5 , y para restar de ella es 0. La resta de requiere un poco de manejo adicional ya que necesita el
\-
combo de comandos, pero los otros solo usan su valor para buscar el carácter de comando apropiado en una tabla.Este proceso se repite para cada comando, construyendo la salida en una cadena preconstruida en la línea 8. Cada vez que se agrega un comando adicional, también agregamos una cita de cierre a la cadena para asegurarnos de que siempre finalice correctamente. Luego, cuando finalmente llegamos al final de nuestra entrada, simplemente "ejecutamos" esta cadena para empujarla a la pila, luego seguimos eso con una secuencia de salida estándar para escribir todo.
fuente
JavaScript (ES6), 163 bytes
Intentalo:
fuente
Vim
208171168 bytesSe agregó la capacidad de hacer varias repeticiones seguidas según @ Flp.Tkc, pero obtuve suficientes bytes como para poder reducir el recuento de bytes.
TryItOnline
Caracteres no imprimibles:
Salida de casos de prueba:
cw^R=^R" ^[
TryItOnlinecw^R=((^R" /5) *-1+9) ^[
TryItOnlinecw^R=((((((^R" +5) +10) *2) -15) -15) /2) ^[
TryItOnlinefuente
lex, 246 bytes
Lex apunta a C, por lo que un compilador de C debería compilarlo en algo ejecutable. La biblioteca lexer (
ll
) también necesitaría estar vinculada. Esto puede agregar una penalización de bytes, pero no estoy seguro de cuántos bytes si es así.El programa genera un programa lex (por especificación) que evalúa la expresión matemática de palabras transpilada. El código entre
%{
y%}
es solo para el "transpilador":Entre las dos
%%
líneas está la porción regex / action. La primera regla que debería coincidir seríaT
("Think ...") que construye el preámbulo (los programas lex deben comenzar al menos contener la sección de la regla, yyytext
es el último texto coincidente, por lo que la regla esencialmente siembra el acumulador con la entrada del usuario )Los descartes de programa todas las entradas excepto que que se corresponde, y las otras normas (
ad
,fr
, hastare
) manejan las cláusulas de expresión wordmath con como partido un mínimo como sea posible para ser único. En la mayoría de estos, se establecec
en un infijo de expresión, que se concatena entren
y la última lectura entera cuandoO
se llama (por ejemplo, leer "agregar 9" establecerá el infijo en+=
, v a9
, y la llamadaO
saldrán+=9;
) . (Un aspecto interesante aparte es que "restar de 8" hará ques
lasfr
reglas y las reglas coincidan, pero comoO
solo se llama al número, la regla correctan=-n+8;
es la única expresión que obtiene salida). losre
regla para "repetir" solo llamaO
de nuevo, que genera la última expresión creada (y dado que las coincidencias posteriores se bloquearányytext
, admitir "repetir" es la razón por la que[0-9]+
se requirió la conversión de enteros en la regla). Finalmente, un período hace que se muestre el avance del programa, que solo genera el acumulador y se cierra con el%%
par que indica el final del programa lex de salida.Nota: Ni el programa principal del transpilador ni el programa de salida finalizarán. La entrada de tubería funcionaría o proporcionaría EOF (ctrl-D). Si se requiere la terminación después de la primera entrada, se pueden agregar exit () s.
Para construir / ejecutar:
Prueba 1:
Prueba 2:
Prueba 3:
Prueba 4:
fuente
Pyth,
6967 bytesUn programa que toma la entrada de a
"quoted string"
e imprime el resultado.Banco de pruebas
Cómo funciona
Pyth tiene operadores de prefijo, por lo que las operaciones aritméticas básicas se realizan utilizando
(operator)(operand1)(operand2)
, mientras que la variable preinicializadaQ
proporciona la entrada. Por lo tanto, un programa WordMath transpilado se construye comenzando con la cadena'Q'
, y en cada etapa, anteponiendo el operador, y luego anteponiendo o agregando el operando como necesario.J\Q
EstablecerJ
, la cadena del programa transpilado, a la cadena'Q'
tcQ\,
Divida la entrada en comas y descarte el primer elemento (que es 'Think of a number'
)V
PorqueN
en eso:Iq@N1\r
Si el carácter enN[1]
es'r'
(repetir):=NZ
EstablecerN
enZ
(valor anterior deN
, establecer al final del ciclo for)x"asdm"@N1
Encuentre el índice deN[1]
in"asdm"
(sumar, restar, dividir, multiplicar)@"+-/*"
Indice con eso en"+-/*"
, dando el operador requerido,J-eCN)\.
Ceda la lista de dos elementos[J, -eCN)\.]
, donde el segundo elemento es el último elemento deN
división en el espacio en blanco con los'.'
caracteres eliminados (operando)qh@cN)1\f
Si el primer carácter del segundo elemento deN
división en espacios en blanco es'f'
(restar de):.>
Intercambie los elementos de la lista de dos elementos.+
Combinar el operador y la lista de dos elementos en una lista=Jjd
EstablecerJ
a eso unido en espacios=ZN
EstablecerZ
enN
J
ImpresiónJ
fuente
Pip , 58 bytes
Lástima que aún no he implementado ese operador de resta inversa.
El programa toma un script de WordMath desde stdin y envía el código Pip a stdout. El código que se emite, de manera similar, toma un número de stdin y envía el resultado a stdout. Pruébalo en línea!
Estrategia
Para entradas como esta:
queremos una salida como esta:
que funciona de la siguiente manera:
Ungolfed + explicación
La estructura básica del programa es
{...}Mq^k
, que divideq
(una línea de stdin) enk
(coma-espacio) yM
aplica una función a cada elemento.Dentro de la función, comenzamos manejando el
repeat
caso. La prueba más corta en Pip parece sersNa
(hay un espacio en el comando). Si es así, queremos usara
; si no, usep
, que almacena el comando anterior. Asigne ese valor nuevamente aa
y también ap
(para la próxima vez).Para nuestro valor de retorno, usamos una lista, que está bien porque el formato de salida predeterminado para las listas es concatenar todo junto. El resultado siempre comienza con
Y
. A continuación, necesitamos una tabla de búsqueda para las operaciones.Observe que las longitudes de
add
(4),subtract
(9),divide by
(10),multiply by
(12) ysubtract from
(14) son todas distintas. Observe además que todavía son distintos cuando se toman el mod 7. Por lo tanto, podemos usarlos para indexar en una lista de siete elementos (que contiene cinco fragmentos de código y dos marcadores de posición) para asignar cada comando de WordMath al código Pip apropiado (diseñado de tal manera que el número simplemente se puede concatenar hasta el final):-y+
(subtract from
)y-
(subtract
)y//
(divide by
)y+
(add
)y*
(multiply by
)Para los índices, utilizamos expresiones regulares para obtener el índice del primer dígito en el comando:
a@?`\d`
. También tiramos de la expresión regulary
para su uso futuro. La tabla de búsqueda se genera dividiendo la cadena"-y+ y- y// y+ y* "
ens
(espacio).Todavía tenemos que manejar la primera entrada, que debería traducirse en el código
Yq
. ComoThink of a number
no contiene ningún dígito, el@?
operador devuelve nulo. Usar nil como índice en la tabla de búsqueda también devuelve nil. Nil es falso, por lo que todo lo que tenemos que hacer es agregar el|'q
uso enq
lugar de una operación para este caso.El elemento final de la lista devuelta es el número mismo. Obtenemos esto a través de
a@y
(encontrar todas las coincidencias en el comando de la expresión regular de dígitos que arrancamos anteriormente). Esto devuelve una lista de dígitos, pero nuevamente, no es un problema porque todas las listas se concatenarán cuando salgan. Para la primera entrada,a@y
no coincide con dígitos y da una lista vacía, que no agrega nada a la salida.Por ejemplo
Con entrada
la expresión del mapa da la lista
que, cuando se concatenan, salidas
fuente
Python 2 ,
154153146 bytesCorregido e incluso guardado varios bytes en el proceso. ^ __ ^
Pruébalo en línea!
Basado en la misma estrategia que mi respuesta Pip . Características específicas de Python:
Think of
y el cierre.
se eliminan de la cadena antes de dividir (input()[9:-1]
). El período era demasiado molesto para manejarlo en el bucle principal. Eliminar los primeros nueve caracteres ayuda por una razón diferente (ver más abajo).import re
), usamosrfind(" ")
para encontrar el último espacio en el comando. También podemos usar esto para verificar elrepeat
caso.a number
, en el que está el índice del espacio1
. Este índice llena convenientemente el otro agujero en la tabla de búsqueda. El otro problema con el procesamiento de la etapa de entrada en el bucle principal era la+c[s:]
parte, que resultaría enx=input() number
. Para resolver ese problema, multiplicamos las cadenas porc[0]<"a"
:1
para todos los comandos regulares, en los quec
comienza con un espacio, pero0
para el iniciala number
.fuente
WinDbg,
449388 bytes-61 bytes definiendo alias para código repetido
Inspirado por el uso de LambdaBeta de
#define
. Este enfoque modifica ligeramente la sintaxis de WordMath (,
y.
debe estar delimitado por espacios como las otras palabras, y,
no siguerepeat
), y crea un alias tal que la sintaxis de WordMath modificada es un código WinDbg válido. La última línea hace lo que la pregunta pregunta y transpira al convertir la entrada en la sintaxis modificada.La entrada se toma configurando una cadena en una dirección de memoria y configurando el pseudo registro
$t0
en esa dirección. Nota: esto sobrescribirá elint
at0x2000000
, por lo que si comienza su cadena allí, se sobrescribirá parcialmente.$t0
También se sobrescribirá.Debido a que crea alias, dependiendo de si este código se ha ejecutado antes o después de configurar la cadena, el código de salida será diferente (con alias o no). Desafortunadamente, no encontré una manera de hacer que los alias se expandan correctamente sin estar delimitados por espacios en blanco (lo que significa que el script de WordMath no podría ejecutarse directamente sin transformarse primero).
Cómo funciona:
Salida de muestra, ingresando la cadena antes de ejecutar este código una vez (el programa resultante se parece a WordMath):
Salida de muestra, ingresando la cadena después de que este código se haya ejecutado una vez (los alias se expanden al ingresar la cadena para que el programa resultante no sea tan bonito):
Algunos resultados de muestra más, simplemente usando la sintaxis de WordMath ligeramente modificada:
fuente
Scala, 338 bytes
Pruébalo tú mismo en ideone
Explicación:
fuente