Transpile WordMath


25

Abbiamo visto tutti quei "matematici hax" online che assomigliano a questo:

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

E, per magia, tutti finiscono con il numero 8!


linguaggio

Definiamo un linguaggio di programmazione che utilizza la sintassi del testo sopra, chiamato "WordMath". Gli script di WordMath seguono questo modello:

Think of a number, <commandlist>.

Il che significa sostanzialmente: prendere un numero (come input da STDIN) come accumulatore iniziale, eseguire tutti i comandi su di esso e produrre il risultato.

I comandi sono separati dal delimitatore ,(virgola + spazio). I comandi validi sono (nota che #rappresenta un numero intero non negativo :) :

  • add #/ subtract #- Aggiungi / sottrai il valore dall'accumulatore.
  • divide by #/ multiply by #- floordiv / moltiplica l'accumulatore per il valore dato.
  • subtract from #- Simile a subtract, ma acc = # - accinvece diacc = acc - #
  • repeat- esegui nuovamente l'ultimo comando. Questo non può essere il primo comando, ma è necessario supportare più ripetizioni consecutive.

La sfida

Il tuo compito è quello di creare un programma o una funzione che accetta uno script WordMath valido come input e lo traspone in un programma completo valido, nella stessa lingua in cui si trova il tuo codice.

Ad esempio, se il mio codice è in Python 2 e lo script è:

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

Il programma emesso può essere:

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

O in alternativa:

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

Finché si tratta di un programma completo che accetta input STDINe stampa STDOUTo gli equivalenti più vicini della lingua.


Regole

  • Il programma originale potrebbe presumere che l'input sia sempre uno script WordMath valido.
  • I programmi trasmessi non devono gestire errori matematici come la divisione per 0.
  • I programmi traspilati possono presumere che l'input rappresenti un intero con segno valido, all'interno dell'intervallo di valori standard dell'intero linguaggio.
  • Questo è , quindi vince la soluzione più breve (in byte).
  • È importante solo il numero di byte del programma originale: il codice emesso può durare quanto vuoi!

Script di esempio

Esempio 1:

Think of a number. 

Prendi input, non fare nulla, visualizzalo: il programma cat di WordMath.

Esempio 2:

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

Ricorda che "divide" è la divisione dei piani, quindi per questo programma 6 -> 8, e 29 -> 4.

Esempio 3:

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

Il programma cat esteso!

Esempio 4:

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

Prende un numero e sottrae 3.


Dobbiamo supportare ripetizioni consecutive?
darrylyeo,

1
Possiamo usare float quando è il tipo predefinito della lingua / se non supporta numeri interi?
Rainer P.

@RainerP. solo se la lingua non supporta la divisione di numeri interi / interi
FlipTack

1
Qual è il risultato atteso di -5/3? Arrotondiamo verso 0o verso l'infinito negativo?
Martin Ender,

1
@MartinEnder direi il giro verso l'infinito negativo poiché è la divisione del piano , ma se il tuo linguaggio implementa la divisione dei numeri interi verso 0 va bene lo stesso.
FlipTack

Risposte:


6

05AB1E , 59 56 54 52 byte

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

Provalo online!

Il mio cervello fa male come l'inferno dopo ... Emette nel codice 05AB1E come segue:

  • Think of a Number viene rimosso, a causa di input implicito.
  • Subtract From #copritrici a #s-(swap ae bed eseguire il funzionamento).
  • Subtract #converte in #-.
  • Add #converte in #+.
  • Multiply by #converte in #*.
  • Divide by #converte in #/.
  • Repeat prende tutto ciò che è stato memorizzato per ultimo nel registro e lo concatena.

Ha spiegato:

„, ¡                                                 # 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.

Esempio:

Ingresso:

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

Produzione:

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

Prova la soluzione con input di 10:

Provalo online!

Guardalo su google:

Ecco un link alla stessa equazione digitata in google.


13

Preprocessore C, 362 byte

QUASI l'ho quasi fatto funzionare solo nel preprocessore C, ma il comando di ripetizione risulta essere troppo difficile da implementare. Quindi invece ho usato il preprocessore per trasformare l'input in un array che viene quindi interpretato da un codice aggiuntivo.

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",_);}

L'input deve essere fornito in "input.wm" o semplicemente scaricato nell'origine su quella riga. Ho incluso i suoi byte nel mio conteggio perché immagino che sia un po 'confuso e leggermente contro le regole della sfida, quindi è solo appropriato.

Ad ogni modo, una volta scaricato il tuo sorgente WordMath in input.wm dove un compilatore può trovarlo, dovresti essere in grado di compilare questo, così com'è, con avvisi per produrre un eseguibile che fa ciò che dice la fonte WordMath.


2
Nota: questo purtroppo fallisce con alcuni compilatori quando finisci con la ripetizione. Questo perché gettano uno spazio dopo lo 0 e poi vedono un periodo randagio e non sanno cosa farne.
LambdaBeta,

intelligente, sono impressionato.
cat

7

Retina, 170 byte

Perché chi non vorrebbe vederlo ?!

Ho pensato a quanto sarebbe stato fantastico vedere una soluzione Retina e ho deciso di crearla rapidamente. Ci sono voluti solo un'ora. Come al solito, il conteggio dei byte assume la codifica 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

Provalo online

L'output ha una nuova riga finale che non deve essere copiata durante il test del programma risultante. Il programma non supporta gli aspetti negativi, perché l' intervallo intero standard di Retina (in unario) non lo è.

Spiegazione:

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

Programmi di matematica:

Inserisci:

Aggiungi il numero di quelli all'inizio. Aggiungi 5:

^
1111

Sottrarre:

Rimuovi il numero di quelli dall'inizio. Sottrai 5:

^11111

Sottrai da:

Sostituire l'ingresso 1s con xs. Metti accanto al numero fisso. Rimuovere ripetutamente x1. Sottrai da 10:

1
x
$
1111111111
+`x1

Moltiplicato per:

Sostituisci ognuno 1con un certo numero di essi. Moltiplicare per 3:

1
111

Dividi per:

Questo utilizza il mio programma Retina per Integer Division . Dividi per 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
$*

Temo di non vedere come possa funzionare. Qualunque input provo per i comandi di sottrazione, ottengo risultati interrotti (mancano gli avanzamenti di riga nell'output?). Inoltre non vedo come questo gestisce input negativi o risultati intermedi negativi.
Martin Ender,

@MartinEnder Posso correggere la sottrazione se spieghi perché questo programma semplificato ne dà due nell'output. retina.tryitonline.net/#code=JArCtjE&input=dGVzdAo
mbomb007

Perché $corrisponde alla fine della stringa o davanti a un avanzamento riga finale. Hai bisogno \zse vuoi solo il primo.
Martin Ender l'

4

GNU awk, 139 byte

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

Invocazione:

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

Casi test:

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

Naturalmente un programmatore funzionale preferirebbe restituire una funzione piuttosto che una stringa che rappresenta un programma, ma qui andiamo:

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

Osservazioni: iniziamo sempre con l'aggiunta di zero, altrimenti la traspilazione del banale programma WordMath non fornirebbe abbastanza informazioni per inferire il tipo in cui readviene utilizzato. subtract from npotrebbe essere implementato come (n-), ma io uso ((-)n)per una maggiore uniformità. Nel caso di subtract ncopio subtractdall'input in modo da non doverlo scrivere, ma devo compensare lo spazio mancante alla fine. repeatviene utilizzato come operazione predefinita; insieme a una precedente operazione iniziale vuota, ciò consente di ignorare facilmente le prime quattro parole.

Esempio di utilizzo:

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

Gli altri esempi danno i seguenti risultati:

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

Solo curioso, come genereresti una funzione da restituire invece di una stringa?
Cyoce,

In un linguaggio di programmazione funzionale, creare e comporre una funzione non è più difficile che creare e aggiungere una stringa. hpotrebbe assomigliare a qualcosa h s n r|x<-s.read.init$n=x%r.xed essere chiamato con il primo argomento una funzione simile h(+)n r(e ci deve essere un flipposto da qualche parte per ottenere l'ordine corretto dell'operatore), lo è il caso base _%_=id. La funzione principale può evitare tutto il boilerplate e semplicemente essere t l=id%words l. - Grazie al curry, potrebbe essere visto come un interprete e quell'idea potrebbe portare a una soluzione più semplice e / o più breve.
Christian Sievers,

4

Python 2, 263 258 260 221 byte

Questo potrebbe probabilmente essere ancora molto più breve.

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

Provalo online

Io uso //invece di /, perché l'ultima istruzione avrà un .alla fine, rendendo qualsiasi numero un float. Quindi, al fine di mantenere coerente la divisione, uso la divisione intera.

Output dei casi di test:

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

Se modifichi quel grande blocco di ifs per oil seguente (che penso dovrebbe funzionare) o=[[o+[['+-'['s'in c],'//']['v'in c],'*']['m'in c]+n,n+'-'+o]['f'in c],'input()']['T'in c]:, puoi farlo scendere a 224.
Kade,

@Kade Sì, era ancora leggibile. Non posso averlo.
mbomb007,

@Cyoce No, l'atto stesso di chiamare lambda probabilmente costerebbe più di quanto risparmi. Dovrebbe salvare 4 o 5 byte per chiamata per pagare.
mbomb007,

4

Befunge, 342 305 byte

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

Provalo online!

Produzione

Il codice che genera inizia con un &comando (valore di input) e termina con i comandi .(valore di output) e @(exit). Nel mezzo abbiamo i vari calcoli nel modulo <number><operation>, dove l' operazione può essere +(aggiungi), -(sottrai), /(dividi per), *(moltiplica per) e \-(sottrai da).

Il numero stesso è un po 'complicato, perché Befunge supporta solo valori letterali numerici compresi tra 0 e 9, quindi tutto ciò che è più grande di quello deve essere calcolato manualmente. Dato che stiamo già leggendo i numeri carattere per carattere, costruiamo semplicemente il numero man mano che ogni cifra viene letta, quindi ad esempio 123 diventa 155+*2+55+*3+, ad es (((1 * 10) + 2) * 10) + 3.

Esempi

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

Spiegazione

Befunge non ha la capacità di manipolare le stringhe in quanto tali, quindi la maggior parte dell'analisi viene gestita contando i caratteri. Iniziamo semplicemente saltando i primi 18 caratteri, che ci fa superare la frase Think of a number (più una virgola o un punto). Quindi se il carattere successivo è una forma di newline o EOF, andiamo direttamente alla routine di output, altrimenti continuiamo a cercare un elenco di comandi.

Per analizzare un comando, continuiamo a contare i caratteri fino a quando non raggiungiamo una cifra o un separatore. Se è un separatore, deve essere stato il comando repeat che gestiamo come caso speciale. Se è una cifra, la aggiungiamo al nostro buffer di output e continuiamo a cercare altre cifre. Ogni volta che viene emessa una cifra, la prefichiamo con 55+*(per moltiplicare il totale finora per 10) e la suffichiamo con +(per aggiungerla al totale). Una volta terminate le cifre, aggiungiamo il carattere di comando.

Per quanto riguarda come viene determinato il comando, prendiamo il conteggio dei caratteri fino alla prima cifra modulo 7. Per aggiungere questo è 4 (incluso il seguente spazio), per sottrarre è 2, per dividere per 3, per moltiplicare per 5 e per sottrarre da 0. Lo sottrazione richiede una piccola gestione aggiuntiva poiché ha bisogno della \-combinazione di comandi, ma gli altri usano semplicemente il loro valore per cercare il carattere di comando appropriato in una tabella.

Questo processo si ripete per ogni comando, costruendo l'output in una stringa precostruita sulla riga 8. Ogni volta che viene aggiunto un comando aggiuntivo, aggiungiamo anche una virgoletta di chiusura alla stringa per assicurarci che sia sempre correttamente terminata. Quindi, quando alla fine raggiungiamo la fine del nostro input, semplicemente "eseguiamo" questa stringa per inserirla nello stack, quindi seguirla con una sequenza di output standard per scrivere tutto.


3

JavaScript (ES6), 163 byte

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

Provalo:

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 byte

Aggiunta la possibilità di eseguire più ripetizioni di seguito come da @ Flp.Tkc ma ho eliminato abbastanza byte da poter ancora ridurre il numero di byte.

: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

Caratteri non stampabili:

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

Output dei casi di test:

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

Questo non sembra funzionare per più ripetizioni consecutive.
FlipTack,

@ Flp.Tkc risolto, grazie! Non me ne sono accorto prima.
nmjcman101,

2

lex, 246 byte

%{
#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 punta a C, quindi un compilatore C dovrebbe compilarlo in qualcosa di eseguibile. Anche la libreria lexer ( ll) dovrebbe essere collegata. Questo può aggiungere una penalità di byte, ma non sono sicuro di quanti byte in tal caso.

Il programma genera un programma lex (per specifica) che valuta l'espressione di parole matematiche traspilate. Il codice tra %{e %}è solo per il "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 */

Tra le due %%righe c'è la parte regex / action. La prima regola da abbinare sarebbe T("Pensa ...") che costruisce il preambolo (i programmi lex devono iniziare almeno con la sezione della regola, ed yytextè l'ultimo testo corrispondente, quindi la regola essenzialmente semina l'accumulatore con l'input dell'utente ).

I rigetti programma tutti gli input tranne per ciò che corrisponde, e le altre modalità ( ad, fr, fino a re) gestire le clausole espressione wordmath con un incontro come minimo possibile per essere unico. Nella maggior parte di questi, si imposta csu un'espressione infix, che viene concatenata tra ne l'ultimo numero intero letto quando Oviene chiamato (quindi, ad esempio, la lettura di "add 9" imposterà infix su +=, v to 9, e la chiamata a Overrà emessa n+=9;) . (A parte un interessante è che "sottrarre da 8" farà sì che sia il se le frregole per ottenere abbinati, ma dal momento che Oviene chiamato solo il numero, la regola appropriata n=-n+8;è l'unica espressione che ottiene in uscita). La reregola per "ripetere" chiama soloOdi nuovo, che genera l'ultima espressione creata (e poiché le corrispondenze successive ostruiscono yytext, è necessario il motivo per cui "ripetere" è il motivo per cui è [0-9]+stata richiesta la conversione di numeri interi nella regola). Infine, un periodo provoca l'uscita del trailer del programma, che genera semplicemente l'accumulatore e si chiude con la %%coppia che indica la fine del programma lex di output.

Nota: Né il programma principale del transpiler né il programma di output verranno chiusi. Il piping input funzionerebbe, o fornendo EOF (ctrl-D). Se è richiesta la terminazione dopo il primo input, è possibile aggiungere exit ().

Per compilare / eseguire:

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
%

Test 1:

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

Test 2:

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

Test 3:

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

Test 4:

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

2

Pyth, 69 67 byte

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

Un programma che accetta input di a "quoted string"e stampa il risultato.

Suite di test

Come funziona

Pyth ha operatori prefissi, quindi le operazioni aritmetiche di base vengono eseguite usando (operator)(operand1)(operand2), mentre la variabile preinizializzata Qfornisce l'input. Quindi, un programma WordMath traspilato viene creato iniziando con la stringa 'Q'e in ciascuna fase, anteponendo l'operatore e quindi anteponendo o aggiungendo l'operando come necessario.

J\QImpostare J, la stringa di programma traspilata, sulla stringa'Q'

tcQ\, Dividi l'input tra virgole e scarta il primo elemento (che è ' Think of a number')

V Per Nquello che:

  • Iq@N1\r Se il carattere N[1]è 'r'(ripetere):
    • =NZImpostato Nsu Z(valore precedente di N, impostato alla fine di per il ciclo)
  • x"asdm"@N1 Trova l'indice di N[1]in "asdm"(aggiungi, sottrai, dividi, moltiplica)
  • @"+-/*" Indicizza con quello in "+-/*", dando l'operatore richiesto
  • ,J-eCN)\. Rende l'elenco di due elementi [J, -eCN)\.] , in cui il secondo elemento è l'ultimo elemento di Ndivisione su spazi bianchi con qualsiasi '.'carattere rimosso (operando)
  • qh@cN)1\f Se il primo carattere del secondo elemento di N divisione nello spazio bianco è 'f'(sottrai da):
    • .> Scambia gli elementi dell'elenco a due elementi
  • + Unire l'operatore e l'elenco a due elementi in un elenco
  • =Jjd Impostato J su quello unito negli spazi
  • =ZN Imposta ZsuN

J Stampare J


Bella risposta amico ... Mi ha ispirato a provare in 05AB1E, che ... Era più intimidatorio del previsto.
Magic Octopus Urn

2

seme , 58 byte

Peccato non ho ancora implementato quell'operatore di sottrazione inversa.

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

Il programma prende uno script WordMath da stdin e invia il codice Pip a stdout. Il codice che viene emesso, allo stesso modo, prende un numero da stdin e invia il risultato a stdout. Provalo online!

Strategia

Per input come questo:

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

vogliamo un output come questo:

YqYy*3Yy+1

che funziona come segue:

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 + spiegazione

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

La struttura di base del programma è {...}Mq^k, che si divide q(una linea di stdin) suk (spazio-virgola) e Mapplica una funzione a ciascun elemento.

All'interno della funzione, iniziamo gestendo il repeatcaso. Il test più breve in Pip sembra essere sNa(c'è uno spazio nel comando). In tal caso, vogliamo usare a; in caso contrario, utilizzare p, che memorizza il comando precedente. Assegna quel valore a ae anche ap (per la prossima volta).

Per il nostro valore di ritorno, utilizziamo un elenco, il che va bene perché il formato di output predefinito per gli elenchi è di concatenare tutto insieme. Il risultato inizia sempre con Y. Successivamente, abbiamo bisogno di una tabella di ricerca per le operazioni.

Osservare che le lunghezze di add (4), subtract (9), divide by (10), multiply by (12) e subtract from (14) sono tutte distinte. Inoltre osserva che sono ancora distinti quando presi mod 7. Quindi, possiamo usarli per indicizzare in un elenco di sette elementi (contenente cinque frammenti di codice e due segnaposto) per mappare ogni comando WordMath sul codice Pip appropriato (progettato in modo che il numero può essere semplicemente concatenato fino alla fine):

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

Per gli indici, usiamo espressioni regolari per ottenere l'indice della prima cifra nel comando: a@?`\d`. Abbiamo anche strappato la regex yper un uso futuro. La tabella di ricerca viene generato dalla scissione della corda "-y+ y- y// y+ y* "sullas (spazio).

Dobbiamo ancora gestire la prima voce, che dovrebbe tradursi nel codice Yq. Poiché Think of a numbernon contiene cifre, l' @?operatore restituisce zero. L'uso di zero come indice nella tabella di ricerca restituisce anche zero. Lo zero è falso, quindi tutto ciò che dobbiamo fare è aggiungere |'qda usare qanziché un'operazione per questo caso.

L'elemento finale dell'elenco restituito è il numero stesso. Otteniamo questo tramite a@y(trova tutte le corrispondenze nel comando della regex digit che abbiamo strappato in precedenza). Ciò restituisce un elenco di cifre, ma ancora una volta, non è un problema perché tutti gli elenchi verranno concatenati durante l'output. Per la prima voce,a@y non corrisponde a cifre e fornisce un elenco vuoto, che non aggiunge nulla all'output.

Per esempio

Con input

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

l'espressione della mappa fornisce l'elenco

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

che, una volta concatenato, genera

YqY-y+20Yy+2Yy+2

2

Python 2 , 154 153 146 byte

Risolto e persino salvato diversi byte nel 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"

Provalo online!

Basato sulla stessa strategia della mia risposta Pip . Funzionalità specifiche di Python:

  • Think of e la chiusura .viene rimossa dalla stringa prima di dividere ( input()[9:-1]). Il periodo era troppo fastidioso da gestire nel ciclo principale. La rimozione dei primi nove caratteri aiuta per un motivo diverso (vedi sotto).
  • Invece di ottenere la lunghezza di ciascun comando cercando regex una cifra (costosa in Python perché import re), usiamo rfind(" ")per trovare l'ultimo spazio nel comando. Possiamo anche usarlo per verificare il repeatcaso.
  • Python non ha l'indicizzazione ciclica di Pip, quindi dobbiamo prendere esplicitamente l'indice mod 7. D'altra parte, ciò significa che possiamo rimuovere l'ultimo valore fittizio nella tabella di ricerca, poiché l'indice mod 7 non è mai 6.
  • Il "comando" la prima volta è a number, in cui è l'indice dello spazio 1. Questo indice riempie comodamente l'altro foro nella tabella di ricerca. L'altro problema con l'elaborazione dello stadio di input nel loop principale era la +c[s:]parte, che avrebbe comportato x=input() number. Per risolvere questo problema, moltiplichiamo per stringa c[0]<"a": 1per tutti i comandi regolari, in cui cinizia con uno spazio, ma 0per l'iniziale a number.

1

WinDbg, 449 388 byte

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 byte definendo l'alias per il codice ripetuto

Ispirato dall'uso di LambdaBeta di #define. Questo approccio modifica leggermente la sintassi di WordMath ( ,e .deve essere delimitata da spazi come le altre parole e ,non seguerepeat ) e crea un alias tale che la sintassi di WordMath modificata sia un codice WinDbg valido. L'ultima riga fa ciò che la domanda pone e traspila convertendo l'input nella sintassi modificata.

L'input viene preso impostando una stringa su un indirizzo di memoria e impostando lo pseudo-registro $t0su quell'indirizzo. Nota: questo sovrascriverà intat 0x2000000, quindi se inizi la tua stringa lì, sarà parzialmente sovrascritto.$t0verrà anche sovrascritto.

Poiché crea alias, a seconda che questo codice sia stato eseguito prima o dopo l'impostazione della stringa, il codice di output sarà diverso (alias o no). Sfortunatamente, non ho trovato il modo di far espandere correttamente gli alias senza essere delimitati da spazi bianchi (il che significa che lo script WordMath non poteva essere eseguito direttamente senza essere prima trasformato).

Come funziona:

* $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 " ."

Output di esempio, immettendo la stringa prima di eseguire questo codice una volta (il programma risultante è simile 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

Output di esempio, immettendo la stringa dopo che questo codice è stato eseguito una volta (gli alias vengono espansi quando si inserisce la stringa in modo che il programma risultante non sia così carino):

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

Qualche ulteriore output di esempio, usando semplicemente la sintassi di WordMath leggermente modificata:

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 byte

Provalo tu stesso su 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)")}

Spiegazione:

// 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)")
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.