Transpile WordMath

25

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 a subtract, pero lo hace en acc = # - acclugar 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 STDINe 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 , 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.

FlipTack
fuente
¿Tenemos que soportar repeticiones consecutivas?
darrylyeo
1
¿Podemos usar flotantes cuando ese es el tipo predeterminado del idioma / si no admite enteros?
Rainer P.
@RainerP. solo si el idioma no admite enteros / división de enteros
FlipTack
1
¿Cuál es el resultado esperado de -5/3? ¿Redondeamos hacia 0o hacia el infinito negativo?
Martin Ender
1
@MartinEnder Diría que es redondo hacia el infinito negativo, ya que es la división de piso , pero si su lenguaje implementa la división de enteros hacia 0, también está bien.
FlipTack

Respuestas:

6

05AB1E , 59 56 54 52 bytes

„, ¡¦vyDþs.AJá'bK"dmas""/*+-"‡„-f„s-.:«D'rQi®}©}J'rK

Prué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 intercambio ay by 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:

„, ¡                                                 # Split on ', '.
    ¦                                                # Remove the 'Think of a number'.
     vy                                        }     # Loop through chunks.
       Dþs                                           # Dupe, push only digits, swap.
          .AJá                                       # Acronymify without digits.
              'bK                                    # Remove the `b`.
                 "dmas""/*+-"‡                       # Replace letters with OPs.
                              „-f„s-.:               # Replace '-f' with 's-'.
                                      «              # Concat # with OP.
                                       D'rQ          # Dupe, push 1 if OP='r'.
                                           i®}       # If 'r', push last #OP.
                                              ©      # Store current OP.
                                                J'rK # Join, remove remaining r's.

Ejemplo:

Entrada:

Think of a number, divide by 2, multiply by 10, add 8, subtract 6, subtract from 9, repeat, repeat, subtract 41.

Salida:

2/10*8+6-9s-9s-9s-41-

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.

Urna de pulpo mágico
fuente
13

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.

main(){int c[]={
#define Think 
#define of
#define a
#define number 0
#define add 1,
#define subtract 2,
#define from 0,3,
#define multiply 4,
#define divide 5,
#define by
#define repeat 6, 0
#include "input.wm"
,'$'};int _,l,v;scanf("%d", &_);for(int i=1;c[i]-'$';++i){c[i]!=6?l=c[i],v=c[++i]:++i;l==1?_+=v:l==2?_-=v:l==3?_=v-_:l==4?_*=v:_/=v;}printf("%d",_);}

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.

LambdaBeta
fuente
2
Nota: desafortunadamente, esto falla con algunos compiladores cuando termina con la repetición. Esto se debe a que arrojan un espacio después del 0 y luego ven un período perdido y no saben qué hacer con él.
LambdaBeta
inteligente, estoy impresionado.
gato
7

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.

S`, 
\.

T.*
.*¶$$*
\;+`(.*)¶rep.*(¶?)
$1¶$1$2
\d+
$*
.*f.* (1*)
1¶x¶$¶$1¶+`x1¶
m.* 
1¶
di.* (1*)
^¶$1 ¶^(1+) (\1)+1*$¶x$$#+¶1+ 1*¶x0¶x\d+¶$$*
s.* (1*)
^$1¶
a.* 
^¶
\z
¶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:

S`,                 # Split input on ", " putting each command on its own line
\.                  # Remove the period

T.*                 # Think of a number -> .*\n$* (replaces input with unary)
.*¶$$*
\;+`(.*)¶rep.*(¶?)  # Loop, replacing "repeat" with the line before it
$1¶$1$2
\d+                 # Replace all numbers with their unary representation
$*
.*f.* (1*)          # Replace "subtract from " with a subtract from program
1¶x¶$¶$1¶+`x1¶
m.*                 # Replace "multiply by " with a multiply program
1¶
di.* (1*)           # Replace "divide by " by my integer division program
^¶$1 ¶^(1+) (\1)+1*$¶x$$#+¶1+ 1*¶x0¶x\d+¶$$*
s.* (1*)            # Replace "subtract " with a subtraction program
^$1¶
a.*                 # Replace "add " with an addition program
^¶
\z                  # At the end, add a stage to change unary into decimal
¶1

Programas de matemáticas:

Añadir:

Agregue el número de unos al principio. Añadir 5:

^
1111

Sustraer:

Eliminar el número de unos desde el principio. Restar 5:

^11111

Restar de:

Reemplace la entrada 1s con xs. Poner al lado del número fijo. Retirar repetidamente x1. Restar de 10:

1
x
$
1111111111
+`x1

Multiplicar por:

Reemplace cada uno 1con un cierto número de ellos. Multiplicar por 3:

1
111

Dividido por:

Esto usa mi programa Retina para la División de enteros . Dividir por 2:

^                   # Place the fixed divisor before the dividend
11 
^(.+) (\1)+.*$      # Match the divisor, followed by each occurrence in the dividend.
x$#+                # Replace with the number of matches. Trailing ones are dropped
.+ .*               # If there are still two numbers, the result is zero
x0
x\d+                # Replace result (marked with an 'x') with unary
$*
mbomb007
fuente
Me temo que no veo cómo esto puede funcionar. Cualesquiera que sean las entradas que intento para los comandos de resta, obtengo resultados rotos (¿faltan avances de línea en la salida?). Tampoco veo cómo esto maneja entradas negativas o resultados intermedios negativos.
Martin Ender
@MartinEnder Puedo arreglar la resta si explicas por qué este programa simplificado da dos en la salida. retina.tryitonline.net/#code=JArCtjE&input=dGVzdAo
mbomb007
Porque $coincide al final de la cadena o frente a un salto de línea final. Lo necesitas \zsi solo quieres lo primero.
Martin Ender
4

GNU awk, 139 bytes

BEGIN{RS="[,.]";c="{}{";ORS=";"}
/ad/{c="+="$2}
/c/{c="-="$2}
/om/{c="="$3"-$0"}
/l/{c="*="$3}
/v/{c="=int($0/"$3")"}
!NF{c="}1"}
$0="$0"c

Invocación:

$> awk `awk -f wordmath <<< "Think of a number, add 1, repeat, repeat."` <<< 0
$> 3

Casos de prueba:

$> awk -f wordmath <<< "Think of a number."  
$> $0{}{;$0}1;

$> awk -f wordmath <<< "Think of a number, divide by 5, subtract from 9."
$> $0{}{;$0=int($0/5);$0=9-$0;$0}1;

$> awk -f wordmath <<< "Think of a number, add 5, add 10, multiply by 2, subtract 15, repeat, divide by 2."
$> $0{}{;$0+=5;$0+=10;$0*=2;$0-=15;$0-=15;$0=int($0/2);$0}1;
Rainer P.
fuente
4

Haskell, 232 231 bytes

Por supuesto, un programador funcional preferiría devolver una función en lugar de una cadena que representa un programa, pero aquí vamos:

t l="main=getLine>>=print."++""%words l++"(0+).read"
x%((o:_):f:n:r)|o=='m'=h"*"n r|o=='d'=h"`div`"n r|f=="from"=h"(-)"n r
x%(s:n:r)|s=="add"=h"+"n r|s!!0=='s'=h s(' ':n)r
x%(_:r)=x%r++x
_%_=""
h s n r|x<-'(':s++init n++")."=x%r++x

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 readse utiliza. subtract from npodría implementarse como (n-), pero lo uso ((-)n)para mayor uniformidad. En el caso de subtract nque copie el subtractde la entrada para no tener que escribirlo, pero necesito compensar el espacio que falta al final. repeatse 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:

*Main> t "Think of a number. "
"main=getLine>>=print.(0+).read" 

Los otros ejemplos dan los siguientes resultados:

"main=getLine>>=print.((-)9).(`div`5).(0+).read"
"main=getLine>>=print.(`div`2).(subtract 15).(subtract 15).(*2).(+10).(+5).(0+).read"  
"main=getLine>>=print.(subtract 1).(subtract 1).(subtract 1).(0+).read"
Christian Sievers
fuente
Por curiosidad, ¿cómo generaría una función para devolver en lugar de una cadena?
Cyoce
En un lenguaje de programación funcional, crear y componer una función no es más difícil que crear y agregar una cadena. hpodría parecer algo así h s n r|x<-s.read.init$n=x%r.xy llamarse con el primer argumento una función como h(+)n r(y debe haber alguna flipen 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 ser t 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.
Christian Sievers
4

Python 2, 263 258 260 221 bytes

Esto probablemente aún podría ser mucho más corto.

def r(s,o="",p=""):c=s.pop(0);c=[c,p]['re'in c];n=c.split()[-1];o=[[o+[['+-'['s'in c],'//']['v'in c],'*']['m'in c]+n,n+'-'+o]['f'in c],'input()']['T'in c];return s and r(s,"(%s)"%o,c)or o
lambda s:"print "+r(s.split(','))

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:

print input()
print 9.-((input())//5)
print ((((((input())+5)+10)+10)-15)-15)//2.
print (((input())-1)-1)-1
mbomb007
fuente
Si cambia ese gran bloque de ifs por olo 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.
Kade
@Kade Sí, todavía era legible. No puedo tener eso.
mbomb007
@Cyoce No, el simple hecho de llamar a la lambda probablemente costaría más de lo que ahorra. Tendría que ahorrar 4 o 5 bytes por llamada para pagar.
mbomb007
4

Befunge, 342305 bytes

>~$1 +:89+`#v_801p
  v_^#`+85~$<
1+>~:5+88+/3-!#v_$
v`"/":~p8p10+1<>>:"/"`!|
 "+"\5+8p4+:1+^:p11:g10<  >:"+"\2+8p:"*"\3+8p:
_$7%:01g\!#v_\2-7g\:1+:01v^p8+1\"5":p8\"5":g10
#8\"\"$#:0#<^v<p8p8\<g80p<>\#+$#12#p
-/+* >:#,_@  #^p8g10<
".@"<^"&"
10<v0<\g8-\g11:<:p1>#1+g11:p10+g
-:^>1g\-8p1-::#^_$8g^  >$$01g11g

Prué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

Input:  Think of a number.
Output: &.@

Input:  Think of a number, divide by 5, subtract from 9.
Output: &5/9\-.@

Input:  Think of a number, add 5, add 10, multiply by 2, subtract 15, repeat, divide by 2.
Output: &5+155+*0++2*155+*5+-155+*5+-2/.@

Input:  Think of a number, subtract 1, repeat, repeat.
Output: &1-1-1-.@

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.

James Holderness
fuente
3

JavaScript (ES6), 163 bytes

w=>w.split`, `.map(l=>(o={a:'+',s:'-',m:'*',d:'/'}[a=l[0]])?p=(x=l.split` `.pop(),l[9]=='f'?x+`-n`:`n`+o+x+`|0`):a<'r'?'n=+prompt()':p).join`
n=`+`
console.log(n)`

Intentalo:

f=w=>w.split`, `.map(l=>(o={a:'+',s:'-',m:'*',d:'/'}[a=l[0]])?p=(x=l.split` `.pop(),l[9]=='f'?x+`-n`:`n`+o+x+`|0`):a<'r'?'n=+prompt()':p).join`
n=`+`
console.log(n)`

const program = f('Think of a number, add 5, add 10, multiply by 2, subtract 15, repeat, divide by 2.')
document.write('<pre>' + program + '</pre>' )

eval(program)

/*
Outputs:

n=+prompt()
n=n+5|0
n=n+10|0
n=n*2|0
n=n-15|0
n=n-15|0
n=n/2.|0
console.log(n)
*/

Darrylyeo
fuente
3

Vim 208 171 168 bytes

Se agregó la capacidad de hacer varias repeticiones seguidas según @ Flp.Tkc, pero obtuve suficientes bytes como para poder reducir el recuento de bytes.

:map s :s;\v
c4wcw="s, s\w* \w+ (\d+); *-1+\1);g
s, ([adms]).{-}(\d+); \1\2);g
qws(\S+), r\w+;\1 \1
@wq@ws.*;\=tr(submatch(0),'adms','+/*-')
qq])T=i(@qq@qx$xA

TryItOnline

Caracteres no imprimibles:

:map s :s;\v
c4wcw^V^R=^V^R"^[s, s\w* \w+ (\d+); *-1+\1);g
s, ([adms]).{-}(\d+); \1\2);g
qws(\S+), r\w+;\1 \1
@wq@ws.*;\=tr(submatch(0),'adms','+/*-')
qq])T=i(^[@qq@qx$xA
^V^[^[

Salida de casos de prueba:

  1. cw^R=^R" ^[ TryItOnline
  2. cw^R=((^R" /5) *-1+9) ^[ TryItOnline
  3. cw^R=((((((^R" +5) +10) *2) -15) -15) /2) ^[ TryItOnline
nmjcman101
fuente
Esto no parece funcionar para múltiples repeticiones consecutivas.
FlipTack
@ Flp.Tkc arreglado, ¡gracias! No me di cuenta de eso antes.
nmjcman101
2

lex, 246 bytes

%{
#define P printf
#define O P("n%s%d;",c,v);
int v;char*c;
%}
%%
T {P("%%%%\n.* {int n=atoi(yytext);");}
ad {c="+=";}
fr {c="=-n+";}
s {c="-=";}
v {c="/=";}
l {c="*=";}
re {O}
[0-9]+ {v=atoi(yytext);O}
\. P("printf(\"%%d\",n);}\n%%%%");
. ;
%%

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":

#define P printf              /* for brevity */
#define O P("n%s%d;",c,v)     /* expression builder, calls P = printf */
int v;char*c;                 /* v=most recent integer read */
                              /* c=the expression infix */

Entre las dos %%líneas está la porción regex / action. La primera regla que debería coincidir sería T("Think ...") que construye el preámbulo (los programas lex deben comenzar al menos contener la sección de la regla, y yytextes 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, hasta re) 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 establece cen un infijo de expresión, que se concatena entre ny la última lectura entera cuando Ose llama (por ejemplo, leer "agregar 9" establecerá el infijo en +=, v a 9, y la llamada Osaldrá n+=9;) . (Un aspecto interesante aparte es que "restar de 8" hará que slas frreglas y las reglas coincidan, pero como Osolo se llama al número, la regla correcta n=-n+8;es la única expresión que obtiene salida). losre regla para "repetir" solo llamaOde nuevo, que genera la última expresión creada (y dado que las coincidencias posteriores se bloquearán yytext, 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:

Build the main program:
% lex -o wordmath.yy.c wordmath.l
% cc -o wordmath wordmath.yy.c -ll

Execute to create a specific transpiled program:
% echo "This is a number, add 8, subtract 5, repeat." | ./wordmath > program.l

Build the transpiled program:
% lex -o program.yy.c program.l
% cc -o program program.yy.c -ll

Execute the transpiled program (with input 3, called via a pipe or inline):
% echo 3 | ./program
1
% ./program
3
1
^D
%

Prueba 1:

%%
.* {int n=atoi(yytext);printf("%d",n);}
%%

Prueba 2:

%%
.* {int n=atoi(yytext);n/=5;n=-n+9;printf("%d",n);}
%%

Prueba 3:

%%
.* {int n=atoi(yytext);n+=5;n+=10;n*=2;n-=15;n-=15;n/=2;printf("%d",n);}
%%

Prueba 4:

%%
.* {int n=atoi(yytext);n-=1;n-=1;n-=1;printf("%d",n);}
%%
ryounce
fuente
2

Pyth, 69 67 bytes

J\QVtcQ\,Iq@N1\r=NZ)=Jjd+@"+-/*"x"asdm"@N1.>,J-ecN)\.qh@cN)1\f=ZN)J

Un 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 preinicializada Qproporciona 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\QEstablecer J, 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 Porque Nen eso:

  • Iq@N1\r Si el carácter en N[1]es 'r'(repetir):
    • =NZEstablecer Nen Z(valor anterior de N, establecer al final del ciclo for)
  • x"asdm"@N1 Encuentre el índice de N[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 de Ndivisión en el espacio en blanco con los '.'caracteres eliminados (operando)
  • qh@cN)1\f Si el primer carácter del segundo elemento de Ndivisió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 Establecer Ja eso unido en espacios
  • =ZN Establecer ZenN

J Impresión J

TheBikingViking
fuente
Buena respuesta hombre ... Me inspiró a intentarlo en 05AB1E, que ... Fue más intimidante de lo previsto.
Urna de pulpo mágico
2

Pip , 58 bytes

Lástima que aún no he implementado ese operador de resta inversa.

{p:a:sNa?ap['Y("-y+  y- y// y+ y* "^sa@?Y`\d`)|'qa@y]}Mq^k

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:

Think of a number, multiply by 3, add 1.

queremos una salida como esta:

YqYy*3Yy+1

que funciona de la siguiente manera:

Yq    Yank a line of stdin into y
Yy*3  Compute y*3 and yank result into y
Yy+1  Compute y+1 and yank result into y
      Last expression is autoprinted

Ungolfed + explicación

{
 p : a : sNa ? a p
 [
  'Y
  ("-y+  y- y// y+ y* "^s a@?Y`\d`) | 'q
  a@y
 ]
} M q^k

La estructura básica del programa es {...}Mq^k, que divide q(una línea de stdin) en k(coma-espacio) y Maplica una función a cada elemento.

Dentro de la función, comenzamos manejando el repeatcaso. La prueba más corta en Pip parece ser sNa(hay un espacio en el comando). Si es así, queremos usar a; si no, use p, que almacena el comando anterior. Asigne ese valor nuevamente a ay también a p(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) y subtract 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):

  • 0: -y+( subtract from)
  • 1: marcador de posición
  • 2: y-( subtract)
  • 3: y//( divide by)
  • 4: y+( add)
  • 5: y*( multiply by)
  • 6: marcador de posición

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 regular ypara su uso futuro. La tabla de búsqueda se genera dividiendo la cadena "-y+ y- y// y+ y* "en s(espacio).

Todavía tenemos que manejar la primera entrada, que debería traducirse en el código Yq. Como Think of a numberno 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 |'quso en qlugar 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@yno coincide con dígitos y da una lista vacía, que no agrega nada a la salida.

Por ejemplo

Con entrada

Think of a number, subtract from 20, add 2, repeat.

la expresión del mapa da la lista

[["Y";"q";[]]; ["Y";"-y+";[2;0]]; ["Y";"y+";[2]]; ["Y";"y+";[2]]]

que, cuando se concatenan, salidas

YqY-y+20Yy+2Yy+2
DLosc
fuente
2

Python 2 , 154 153 146 bytes

Corregido e incluso guardado varios bytes en el proceso. ^ __ ^

for c in input()[9:-1].split(","):s=c.rfind(" ");p=o=s and"x="+"-x+ input() x- x// x+ x*".split()[s%7]+c[s:]*(c[0]<"a")or p;print o
print"print x"

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).
  • En lugar de obtener la longitud de cada comando buscando expresiones de un dígito (caro en Python porque import re), usamos rfind(" ")para encontrar el último espacio en el comando. También podemos usar esto para verificar el repeatcaso.
  • Python no tiene la indexación cíclica de Pip, por lo que tenemos que tomar el índice mod 7 explícitamente. Por otro lado, esto significa que podemos eliminar el último valor ficticio en la tabla de búsqueda, ya que el índice mod 7 nunca es 6.
  • El "comando" la primera vez es a number, en el que está el índice del espacio 1. 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 en x=input() number. Para resolver ese problema, multiplicamos las cadenas por c[0]<"a": 1para todos los comandos regulares, en los que ccomienza con un espacio, pero 0para el inicial a number.
DLosc
fuente
1

WinDbg, 449 388 bytes

as, }@$t1
as. }0;?@$t0
asThink n10;ed8<<22;r$t0=dwo(8<<22);r$t1=0;.do{
aSa " "
asQ .printf";r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0
as/c add Q +"
aSby " "
as/c divide Q /"
asfrom 0;r$t0=-@$t0+
as/c multiply Q *"
aSnumber " "
aSof " "
asrepeat +1
as/c subtract Q -"
.for(r$t9=1;by(@$t0);r$t0=@$t0+1){j44!=by(@$t0) .printf"%c",by(@$t0);.if116!=by(@$t0-1){.printf" , "}};.printf"\b ."

-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 $t0en esa dirección. Nota: esto sobrescribirá el intat 0x2000000, por lo que si comienza su cadena allí, se sobrescribirá parcialmente.$t0Tambié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:

* $t1 is used for repeating and $t0 is used to read the input and hold the accumulator
* Alias , to }@$t1 -- closing do-while loop and allowing repeat
as , }@$t1

* Alias . to }0;?@$t0 -- close do-while loop and evaluate $t0 (accumulator)
as . }0;?@$t0

* Alias Think to (note this is one line)
as Think n10;               * Set base 10
         ed 8<<22;          * Read ints to address 0x2000000. Enter nothing to exit input mode
         r$t0 = dwo(8<<22); * Set $t0 = first int
         r$t1=0;.do{        * Open do-while

* Alias a to nothing
aS a " "

* Alias add to (note one line):
as add ;                       * Close previous statement
       r$t1=1;.do{r$t1=@$t1-1; * Open do-while (once) loop
       r$t0=@$t0+              * Add number to $t0

* Alias by to nothing
aS by " "

* Alias divide to (note one line):
as divide ;                       * Close previous statement
          r$t1=1;.do{r$t1=@$t1-1; * Open do-while (once) loop
          r$t0=@$t0/              * Divide next number from $t0

* Alias from to (note one line):
as from 0;         * Preceding subtract statement subtracts 0
       r$t0=-@$t0+ * Subtract $t0 from next number

* Alias multiply to (note one line):
as multiply ;                       * Close previous statement
            r$t1=1;.do{r$t1=@$t1-1; * Open do-while (once) loop
            r$t0=@$t0*              * Multiply next number with $t0

* Alias number to nothing
aS number " "

* Alias of to nothing
aS of " "

* Alias repeat to +1 making do-while (once) loops into do-while (once)+1
as repeat +1

* Alias subtract to (note one line):
as subtract ;                       * Close previous statement
            r$t1=1;.do{r$t1=@$t1-1; * Open do-while (once) loop
            r$t0=@$t0-              * Subtract next number from $t0


.for (r$t9=1; by(@$t0); r$t0=@$t0+1) * Enumerate the string
{
    j 44!=by(@$t0)                   * If not comma
        .printf "%c",by(@$t0);       * Print the char
    * implicit else
        .if 116!=by(@$t0-1)          * Else if the previous char is not t
        {
          .printf " , "              * Print the comma with spaces around it
        }
};
.printf "\b ."                       * Replacing ending "." with " ."

Salida de muestra, ingresando la cadena antes de ejecutar este código una vez (el programa resultante se parece a WordMath):

0:000> r$t0=8<<22
0:000> eza8<<22"Think of a number, add 5, add 10, multiply by 2, subtract 15, repeat, divide by 2."
0:000> as, }@$t1
0:000> as. }0;?@$t0
0:000> asThink n10;ed8<<22;r$t0=dwo(8<<22);r$t1=0;.do{
0:000> aSa " "
0:000> asadd ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0+
0:000> aSby " "
0:000> asdivide ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0/
0:000> asfrom 0;r$t0=-@$t0+
0:000> asmultiply ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0*
0:000> aSnumber " "
0:000> aSof " "
0:000> asrepeat +1
0:000> assubtract ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0-
0:000> .for(r$t9=1;by(@$t0);r$t0=@$t0+1){j44!=by(@$t0) .printf"%c",by(@$t0);.if116!=by(@$t0-1){.printf" , "}};.printf"\b ."
Think of a number ,  add 5 ,  add 10 ,  multiply by 2 ,  subtract 15 ,  repeat divide by 2 }0;?@$t0

0:000> Think of a number ,  add 5 ,  add 10 ,  multiply by 2 ,  subtract 15 ,  repeat divide by 2 }0;?@$t0
base is 10
02000000 6e696854 18
18
02000004 666f206b 

Evaluate expression: 18 = 00000012

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):

0:000> r$t0=8<<22
0:000> eza8<<22"Think of a number, add 5, add 10, multiply by 2, subtract 15, repeat, divide by 2."
0:000> as, }@$t1
0:000> as. }0;?@$t0
0:000> asThink n10;ed8<<22;r$t0=dwo(8<<22);r$t1=0;.do{
0:000> aSa " "
0:000> asadd ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0+
0:000> aSby " "
0:000> asdivide ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0/
0:000> asfrom 0;r$t0=-@$t0+
0:000> asmultiply ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0*
0:000> aSnumber " "
0:000> aSof " "
0:000> asrepeat +1
0:000> assubtract ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0-
0:000> .for(r$t9=1;by(@$t0);r$t0=@$t0+1){j44!=by(@$t0) .printf"%c",by(@$t0);.if116!=by(@$t0-1){.printf" , "}};.printf"\b ."
n10;ed8<<22;r$t0=dwo(8<<22);r$t1=0;.do{     number ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0+ 5 ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0+ 10 ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0*   2 ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0- 15 ,  repeat ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0/   2 }0;?@$t0

0:000> n10;ed8<<22;r$t0=dwo(8<<22);r$t1=0;.do{     number ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0+ 5 ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0+ 10 ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0*   2 ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0- 15 ,  repeat ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0/   2 }0;?@$t0
base is 10
02000000 3b30316e 26
26
02000004 3c386465 

Evaluate expression: 26 = 0000001a

Algunos resultados de muestra más, simplemente usando la sintaxis de WordMath ligeramente modificada:

0:000> Think of a number , add 1 , repeat repeat repeat divide by 3 .
base is 10
02000000 0000001a 3
3
02000004 3c386465 

Evaluate expression: 2 = 00000002


0:000> Think of a number , divide by 5 , subtract from 9 .
base is 10
02000000 00000003 29
29
02000004 3c386465 

Evaluate expression: 4 = 00000004
Leche
fuente
0

Scala, 338 bytes

Pruébalo tú mismo en ideone

s=>{val n=(_:String)filter(_.isDigit)toInt;(Seq("").tail/:s.split(",").tail)((a,&)=> &match{case&if&contains "v"=>a:+"x/="+n(&)
case&if&contains "d"=>a:+"x+="+n(&)
case&if&contains "y"=>a:+"x*="+n(&)
case&if&contains "f"=>a:+"x="+n(&)+"-x"
case&if&contains "s"=>a:+"x-="+n(&)
case p=>a:+a.last})mkString("var x=readInt;",";",";print(x)")}

Explicación:

// define a function with a parameter s
s => {
    // define a function with a String parameter to extract a number from a string
    val n =
        // filter out the chars that arent't digits
        (_: String) filter (_.isDigit)
        // and parse the number
        toInt;
    // take the tail of a list with an empty string,
    // which is the empty list of type Seq[String].
    // This is the start value for the fold...
    (Seq("").tail /:
        // ... of the tail of the sentence splitted at commas
        s.split(",").tail
    ) (
        // This is the function for the fold.
        // a is the accumulator (the list), and the current element is called &
        (a, &) => & match {
            // if & contains a "v", append "x/=" + n(&) to a.
            case & if & contains "v" => a :+ "x/=" + n(&)
            // the other cases are similar
            case & if & contains "d" => a :+ "x+=" + n(&)
            case & if & contains "y" => a :+ "x*=" + n(&)
            case & if & contains "f" => a :+ "x=" + n(&) + "-x"
            case & if & contains "s" => a :+ "x-=" + n(&)
            // for the repeat, apppend the last value of a to a
            case p                   => a :+ a.last
        }
     )
     // make a string out of the parts by joining them with semicolons,
     // prepending "var x=readInt;" and appending ";print(x)"
     mkString("var x=readInt;", ";", ";print(x)")
}
corvus_192
fuente