Transpilar o WordMath


25

Todos nós vimos aqueles "matemáticos hax" on-line que são assim:

Think of a number, divide by 2, multiply by 0, add 8.

E, por mágica, todo mundo acaba com o número 8!


Língua

Vamos definir uma linguagem de programação que use a sintaxe do texto acima, chamada "WordMath". Os scripts do WordMath seguem este modelo:

Think of a number, <commandlist>.

O que basicamente significa: Pegue um número (como entrada de STDIN) como acumulador inicial, execute todos os comandos nele e produza o resultado.

Os comandos são separados pelo delimitador ,(vírgula + espaço). Os comandos válidos são (observe que #representa um número inteiro não negativo :) :

  • add #/ subtract #- Adicione / subtraia o valor do acumulador.
  • divide by #/ multiply by #- floordiv / multiplica o acumulador pelo valor especificado.
  • subtract from #- Semelhante a subtract, mas em acc = # - accvez deacc = acc - #
  • repeat- faça o último comando novamente. Este não pode ser o 1º comando, mas você deve suportar várias repetições consecutivas.

O desafio

Sua tarefa é criar um programa ou função que use um script válido do WordMath como entrada e transpile para um programa completo válido - no mesmo idioma em que seu código está.

Por exemplo, se meu código estiver em Python 2 e o script for:

Think of a number, subtract from 10, add 10, multiply by 2.

O programa emitido pode ser:

a = input()
a = 10 - a
a += 10
a *= 2
print(a)

Ou alternativamente:

print(((10-input())+10)*2)

Desde que seja um programa completo que receba STDINe imprima em STDOUT, ou nos equivalentes mais próximos do idioma.


Regras

  • Seu programa original pode assumir que a entrada é sempre um script válido do WordMath.
  • Os programas transpilados não precisam manipular erros matemáticos, como divisão por 0.
  • Os programas transpilados podem assumir que a entrada representa um número inteiro assinado válido, dentro do intervalo inteiro padrão do seu idioma.
  • Isso é , então a solução mais curta (em bytes) vence.
  • Somente a contagem de bytes do seu programa original é importante - o código emitido pode ser o tempo que você quiser!

Scripts de exemplo

Exemplo 1:

Think of a number. 

Pegue a entrada, não faça nada, exiba-a: o programa para gatos do WordMath.

Exemplo 2:

Think of a number, divide by 5, subtract from 9.

Lembre-se de que "dividir" é divisão de piso, portanto, para este programa 6 -> 8, e 29 -> 4.

Exemplo 3:

Think of a number, add 5, add 10, multiply by 2, subtract 15, repeat, divide by 2.

O programa estendido para gatos!

Exemplo 4:

Think of a number, subtract 1, repeat, repeat.

Pega um número e subtrai 3.


Temos que apoiar repetições consecutivas?
darrylyeo

1
Podemos usar carros alegóricos quando esse é o tipo padrão do idioma / se ele não suporta números inteiros?
Rainer P.

@RainerP. somente se o idioma não suporta inteiros / divisão inteira
FlipTack

1
Qual é o resultado esperado -5/3? Nós arredondamos para 0ou em direção ao infinito negativo?
Martin Ender

1
@MartinEnder Eu diria redondo para o infinito negativo, pois é a divisão do piso , mas se o seu idioma implementa a divisão inteira para 0, tudo bem também.
FlipTack

Respostas:


6

05AB1E , 59 56 54 52 bytes

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

Experimente online!

Meu cérebro dói muito depois disso ... Ele gera no código 05AB1E da seguinte maneira:

  • Think of a Number é removido devido a entrada implícita.
  • Subtract From #abrigos para #s-(swap ae be executar a operação).
  • Subtract #converte para #-.
  • Add #converte para #+.
  • Multiply by #converte para #*.
  • Divide by #converte para #/.
  • Repeat pega o que foi armazenado pela última vez no registro e o 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.

Exemplo:

Entrada:

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

Saída:

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

Experimente a solução com entrada 10:

Experimente online!

Veja no google:

Aqui está um link para a mesma equação digitada no google.


13

Pré-processador C, 362 bytes

Eu quase consegui isso trabalhando apenas no pré-processador C, mas o comando repeat acaba sendo muito difícil de implementar. Então, em vez disso, usei o pré-processador para transformar a entrada em uma matriz que é interpretada por algum 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",_);}

A entrada deve ser fornecida em "input.wm" ou apenas despejada na fonte nessa linha. Incluí os bytes na minha contagem porque acho que é um pouco hacky e um pouco contra as regras do desafio, por isso é apenas adequado.

De qualquer forma, depois de despejar sua fonte do WordMath em input.wm, onde um compilador pode encontrá-lo, você poderá compilar isso, como está, com avisos para produzir um executável que faça o que a fonte do WordMath diz.


2
Nota: isso infelizmente falha com alguns compiladores quando você termina com a repetição. Isso ocorre porque eles lançam um espaço após o 0 e depois veem um período perdido e não sabem o que fazer com ele.
LambdaBeta

esperto, estou impressionado.
cat

7

Retina, 170 bytes

Porque quem não gostaria de ver isso ?!

Pensei em como seria incrível ver uma solução Retina e decidi criá-la rapidamente. Levou apenas uma hora. Como sempre, a contagem de bytes assume a codificação 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

Experimente online

A saída possui uma nova linha à direita que não deve ser copiada ao testar o programa resultante. O programa não suporta negativos, porque o intervalo inteiro padrão da Retina (em unário) não.

Explicação:

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ática:

Adicionar:

Adicione o número de unidades ao início. Adicione 5:

^
1111

Subtrair:

Remova o número de unidades desde o início. Subtraia 5:

^11111

Subtrair de:

Substitua a entrada 1s por xs. Coloque ao lado do número fixo. Remova repetidamente x1. Subtraia de 10:

1
x
$
1111111111
+`x1

Multiplique por:

Substitua todos 1por um certo número deles. Multiplique por 3:

1
111

Dividido por:

Isso usa meu programa Retina para a Divisão Inteira . Divida 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
$*

Receio não ver como isso pode funcionar. Quaisquer que sejam as entradas que eu tento para os comandos de subtração, obtenho resultados quebrados (faltam linhas na saída?). Também não vejo como isso lida com entradas negativas ou resultados intermediários negativos.
Martin Ender

@MartinEnder Posso corrigir a subtração se você explicar por que esse programa simplificado fornece dois na saída. retina.tryitonline.net/#code=JArCtjE&input=dGVzdAo
mbomb007

Porque $combina no final da sequência ou na frente de um avanço de linha à direita. Você precisa \zse você quer apenas o primeiro.
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

Invocação:

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

Casos de teste:

$> 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;

4

Haskell, 232 231 bytes

Obviamente, um programador funcional prefere retornar uma função ao invés de uma string que representa um programa, mas aqui vamos nós:

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

Comentários: Sempre começamos adicionando zero, caso contrário, a transpilação do programa trivial do WordMath não forneceria informações suficientes para inferir o tipo em que readé usado. subtract from npoderia ser implementado como (n-), mas eu uso ((-)n)para mais uniformidade. No caso de subtract ncopiar o subtractda entrada, não preciso escrevê-lo, mas preciso compensar o espaço que falta no final. repeaté usado como operação padrão; juntamente com uma operação anterior inicial vazia, isso permite ignorar facilmente as quatro primeiras palavras.

Exemplo de uso:

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

Os outros exemplos fornecem os seguintes 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"

Apenas curioso, como você geraria uma função para retornar em vez de uma string?
Cyoce 8/12/16

Em uma linguagem de programação funcional, criar e compor uma função não é mais difícil do que criar e anexar uma string. hpode parecer algo h s n r|x<-s.read.init$n=x%r.xe ser chamado no primeiro argumento de uma função como h(+)n r(e precisa haver algum fliplugar para obter a ordem correta do operador), o caso base é _%_=id. A função principal pode evitar todo o padrão e apenas ser t l=id%words l. - Graças ao currying, ele pode ser visto como um intérprete, e essa ideia pode levar a uma solução mais fácil e / ou mais curta.
Christian Sievers

4

Python 2, 263 258 260 221 bytes

Provavelmente ainda poderia ser muito mais curto.

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(','))

Experimente online

Eu uso em //vez de /, porque a última instrução terá um .no final, tornando qualquer número um float. Portanto, para manter a divisão consistente, eu uso a divisão inteira.

Saída de casos de teste:

print input()
print 9.-((input())//5)
print ((((((input())+5)+10)+10)-15)-15)//2.
print (((input())-1)-1)-1

Se você alterar esse grande bloco de ifs para oo seguinte (o que eu acho que deve funcionar):, o=[[o+[['+-'['s'in c],'//']['v'in c],'*']['m'in c]+n,n+'-'+o]['f'in c],'input()']['T'in c]você pode baixá-lo para 224.
Kade

@ Kade Sim, ainda era legível. Não pode ter isso.
mbomb007

@ Cyy Não, o próprio ato de chamar o lambda provavelmente custaria mais do que economiza. Teria que salvar 4 ou 5 bytes por chamada para pagar.
mbomb007

4

Anterior, 342 305 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

Experimente online!

Saída

O código gerado começa com um &comando (valor de entrada) e termina com os comandos .(valor de saída) e @(saída). No meio, temos os vários cálculos no formulário <number><operation>, onde a operação pode ser +(somar), -(subtrair), /(dividir por), *(multiplicar por) e \-(subtrair de).

O número em si é um pouco complicado, porque o Befunge suporta apenas literais numéricos no intervalo de 0 a 9, portanto, qualquer coisa maior que isso precisa ser calculada manualmente. Como já estamos lendo os números caractere a caractere, simplesmente aumentamos o número à medida que cada dígito é lido, por exemplo, 123 se torna 155+*2+55+*3+, ie (((1 * 10) + 2) * 10) + 3.

Exemplos

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-.@

Explicação

O Befunge não tem a capacidade de manipular seqüências de caracteres, portanto, a maior parte da análise é realizada pela contagem de caracteres. Começamos apenas pulando os 18 primeiros caracteres, o que nos leva a pensar em uma frase numérica (mais uma vírgula ou ponto). Então, se o próximo caractere for alguma forma de nova linha ou EOF, iremos diretamente para a rotina de saída, caso contrário, continuaremos procurando uma lista de comandos.

Para analisar um comando, continuamos contando caracteres até chegarmos a um dígito ou separador. Se é um separador, deve ter sido o comando de repetição que tratamos como um caso especial. Se for um dígito, o adicionamos ao nosso buffer de saída e continuamos procurando mais dígitos. Cada vez que um dígito é emitido, o prefixamos com 55+*(para multiplicar o total até agora por 10) e o sufixamos com +(para adicioná-lo ao total). Quando os dígitos terminam, adicionamos o caractere de comando.

Quanto à forma como o comando é determinado, levamos a contagem de caracteres até o primeiro dígito do módulo 7. Para adicionar este é 4 (incluindo o espaço a seguir), para subtrair é 2, para dividir por 3, para multiplicar por 5 , e para subtrair dele é 0. O subtrair de requer um pouco de manipulação adicional, pois precisa da \-combinação de comandos, mas os outros apenas usam seu valor para procurar o caractere de comando apropriado em uma tabela.

Esse processo é repetido para cada comando, construindo a saída em uma sequência pré-construída na linha 8. Cada vez que um comando adicional é adicionado, também adicionamos uma citação final à sequência para garantir que ela seja sempre finalizada corretamente. Então, quando finalmente chegamos ao final de nossa entrada, simplesmente "executamos" essa string para empurrá-la para a pilha e, em seguida, seguimos com uma sequência de saída padrão para escrever tudo.


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

Tente:

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)
*/


3

Vim 208 171 168 bytes

Foi adicionada a capacidade de fazer várias repetições consecutivas, como @ Flp.Tkc, mas gerando bytes suficientes para que eu ainda pudesse diminuir a contagem 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 não imprimíveis:

: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^[^[

Saída de casos de teste:

  1. cw^R=^R" ^[ TryItOnline
  2. cw^R=((^R" /5) *-1+9) ^[ TryItOnline
  3. cw^R=((((((^R" +5) +10) *2) -15) -15) /2) ^[ TryItOnline

Isso não parece funcionar por várias repetições consecutivas.
FlipTack

@ Flp.Tkc corrigido, obrigado! Eu não percebi isso antes.
precisa saber é o seguinte

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 tem como alvo C, portanto, um compilador C precisaria compilá-lo em algo executável. A biblioteca lexer ( ll) também precisaria estar vinculada. Isso pode adicionar uma penalidade de bytes, mas não tenho certeza de quantos bytes, se houver.

O programa gera um programa lex (por especificação) que avalia a expressão de texto transpilado. O código entre %{e %}é apenas para o "transpiler":

#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 as duas %%linhas está a parte regex / action. A primeira regra a ser correspondida seria T("Think ...") que constrói o preâmbulo (os programas lex devem iniciar pelo menos a seção de regras e o yytextúltimo texto correspondente, portanto, a regra basicamente semeia o acumulador com a entrada do usuário )

As devoluções do programa todas as entradas, exceto para o que for compatível, e as outras regras ( ad, fraté re) lidar com as cláusulas de expressão wordmath com como jogo um mínimo possível de ser único. Na maioria deles, ele define cum infixo de expressão, que é concatenado entre ne o último número inteiro lido quando Oé chamado (por exemplo, a leitura de "add 9" definirá o infixo como +=, v para 9, e a chamada Oserá exibida n+=9;) . (Um aspecto interessante é que "subtrair de 8" fará com que sas frregras e as regras sejam correspondidas, mas como Oé chamado apenas no número, a regra apropriada n=-n+8;é a única expressão que obtém saída). A reregra para "repetir" apenas chamaOnovamente, que gera a última expressão criada (e, como as correspondências subseqüentes serão derrotadas yytext, o suporte à "repetição" é o motivo pelo qual a conversão de número inteiro na [0-9]+regra foi necessária). Finalmente, um período faz com que o trailer do programa seja produzido, o que apenas gera o acumulador e fecha com o %%par que indica o final do programa de saída lex.

Nota: Nem o programa principal do transpilador nem o programa de saída serão finalizados. A entrada da tubulação funcionaria ou fornecer EOF (ctrl-D). Se a finalização for necessária após a primeira entrada, é possível adicionar exit () s.

Para criar / executar:

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
%

Teste 1:

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

Teste 2:

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

Teste 3:

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

Teste 4:

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

2

Pitão, 69 67 bytes

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

Um programa que recebe a entrada de "quoted string"e imprime o resultado.

Suíte de teste

Como funciona

Pyth possui operadores de prefixo, portanto, as operações aritméticas básicas são executadas usando (operator)(operand1)(operand2), enquanto a variável pré-inicializada Qfornece a entrada. Portanto, um programa WordMath transpilado é construído iniciando com a sequência 'Q'e, em cada estágio, precedido pelo operador e, em seguida, precedido ou anexado ao operando como necessário.

J\QDefina J, a sequência de programas transpilada, como a sequência'Q'

tcQ\, Divida a entrada por vírgulas e descarte o primeiro elemento (que é ' Think of a number')

V Pois Nnisso:

  • Iq@N1\r Se o caractere em N[1]for 'r'(repita):
    • =NZDefinido Ncomo Z(valor anterior de N, definido no final do loop for)
  • x"asdm"@N1 Encontre o índice de N[1]in "asdm"(adicione, subtraia, divida, multiplique)
  • @"+-/*" Índice com isso em "+-/*", fornecendo o operador necessário
  • ,J-eCN)\.Rendimento da lista de dois elementos [J, -eCN)\.], em que o segundo elemento é o último elemento da Ndivisão no espaço em branco com qualquer '.'caractere removido (operando)
  • qh@cN)1\f Se o primeiro caractere do segundo elemento da Ndivisão no espaço em branco for 'f'(subtrair de):
    • .> Troque os elementos da lista de dois elementos
  • + Mesclar o operador e a lista de dois elementos em uma lista
  • =Jjd Definido Jcomo aquele unido em espaços
  • =ZN Defina ZcomoN

J Impressão J


Boa resposta, cara ... Inspirou-me a experimentar o 05AB1E, que ... Foi mais intimidador do que o previsto.
Magic Octopus Urn

2

Pip , 58 bytes

Pena que ainda não implementei esse operador de subtração reversa.

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

O programa pega um script do WordMath de stdin e gera o código Pip para stdout. O código que é produzido, da mesma forma, pega um número de stdin e gera o resultado em stdout. Experimente online!

Estratégia

Para entrada como esta:

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

queremos uma saída como esta:

YqYy*3Yy+1

que funciona da seguinte maneira:

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 + explicação

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

A estrutura básica do programa é {...}Mq^k, que divide q(uma linha de stdin) em k(vírgula-espaço) e Maps uma função para cada elemento.

Dentro da função, começamos tratando o repeatcaso. O teste mais curto no Pip parece ser sNa(existe um espaço no comando). Se sim, queremos usar a; caso contrário, use p, que armazena o comando anterior. Atribua esse valor de volta para ae também para p(da próxima vez).

Para nosso valor de retorno, usamos uma lista, o que é bom porque o formato de saída padrão para listas é concatenar tudo juntos. O resultado sempre começa com Y. Em seguida, precisamos de uma tabela de pesquisa para as operações.

Observe que os comprimentos de add (4), subtract (9), divide by (10), multiply by (12) e subtract from (14) são todos distintos. Além disso, observe que eles ainda são distintos quando usados ​​no mod 7. Assim, podemos usá-los para indexar em uma lista de sete elementos (contendo cinco trechos de código e dois espaços reservados) para mapear cada comando do WordMath para o código Pip apropriado (projetado para o número pode simplesmente ser concatenado até o final):

  • 0: -y+( subtract from)
  • 1: espaço reservado
  • 2: y-( subtract)
  • 3: y//( divide by)
  • 4: y+( add)
  • 5: y*( multiply by)
  • 6: espaço reservado

Para os índices, usamos regex para obter o índice do primeiro dígito no comando: a@?`\d`. Também puxamos a regex ypara uso futuro. A tabela de pesquisa é gerada dividindo a sequência "-y+ y- y// y+ y* "em s(espaço).

Ainda precisamos lidar com a primeira entrada, que deve ser traduzida no código Yq. Como Think of a numbernão contém dígitos, o @?operador retorna nulo. Usar nil como um índice na tabela de pesquisa também retorna nil. Nada é falso, então tudo o que precisamos fazer é adicionar |'qao uso em qvez de uma operação para este caso.

O elemento final da lista retornada é o próprio número. Obtemos isso via a@y(encontre todas as correspondências no comando do regex de dígitos que arrancamos anteriormente). Isso retorna uma lista de dígitos, mas, novamente, não é um problema, porque todas as listas serão concatenadas na saída. Para a primeira entrada, a@ynão corresponde a nenhum dígito e fornece uma lista vazia, o que não adiciona nada à saída.

Por exemplo

Com entrada

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

a expressão do mapa fornece a lista

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

que, quando concatenado, gera

YqY-y+20Yy+2Yy+2

2

Python 2 , 154 153 146 bytes

Corrigido e até salvo vários bytes no processo. ^ __ ^

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"

Experimente online!

Com base na mesma estratégia da minha resposta Pip . Recursos específicos do Python:

  • Think of e o fechamento .é removido da string antes de dividir ( input()[9:-1]). O período foi muito incômodo para lidar com o loop principal. A remoção dos nove primeiros caracteres ajuda por um motivo diferente (veja abaixo).
  • Em vez de obter o comprimento de cada comando pesquisando um dígito por regex (caro no Python porque import re), usamos rfind(" ")para encontrar o último espaço no comando. Também podemos usar isso para verificar o repeatcaso.
  • O Python não possui a indexação cíclica do Pip, então temos que usar o mod 7 do índice explicitamente. Por outro lado, isso significa que podemos remover o último valor fictício na tabela de pesquisa, pois o índice mod 7 nunca é 6.
  • O "comando" é a primeira vez a numberque o índice do espaço está 1. Esse índice preenche convenientemente o outro orifício na tabela de pesquisa. O outro problema com o processamento do estágio de entrada no loop principal era a +c[s:]parte que resultaria em x=input() number. Para resolver esse problema, multiplicamos por string c[0]<"a": 1para todos os comandos regulares, nos quais ccomeça com um espaço, mas 0para o inicial a number.

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, definindo alias para código repetido

Inspirado pelo uso de LambdaBeta#define . Essa abordagem modifica ligeiramente a sintaxe do WordMath ( ,e .deve ser delimitada por espaço como as outras palavras, e ,não segue repeat) e cria um alias para que a sintaxe do WordMath modificada seja um código WinDbg válido. A última linha faz o que a pergunta pede e transpila, convertendo a entrada na sintaxe modificada.

A entrada é obtida definindo uma sequência em um endereço de memória e configurando o pseudo-registro $t0para esse endereço. Nota: isso substituirá o intat 0x2000000, portanto, se você iniciar sua string lá, ela será parcialmente substituída. $t0também será substituído.

Como ele cria aliases, dependendo se esse código foi executado antes ou depois de definir a sequência, o código de saída será diferente (alias ou não). Infelizmente, não encontrei uma maneira de fazer com que os aliases se expandissem corretamente sem serem delimitados por espaços em branco (o que significa que o script do WordMath não poderia ser executado diretamente diretamente sem ser transformado primeiro).

Como 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 " ."

Exemplo de saída, inserindo a string antes de executar este código uma vez (o programa resultante se assemelha ao 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

Exemplo de saída, inserindo a sequência após a execução desse código uma vez (os aliases são expandidos ao inserir a sequência, para que o programa resultante não seja tão 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

Um pouco mais de exemplo de saída, apenas usando a sintaxe do WordMath ligeiramente 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

0

Scala, 338 bytes

Experimente você mesmo em 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)")}

Explicação:

// 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)")
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.