Transpile WordMath


25

私たちは皆、このようなオンラインの「数学hax」を見てきました。

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

そして、魔法によって、誰もが8番になります!


言語

「WordMath」と呼ばれる上記のテキストの構文を使用するプログラミング言語を定義しましょう。WordMathスクリプトは、次のテンプレートに従います。

Think of a number, <commandlist>.

これは基本的に、最初のアキュムレーターとして(STDINからの入力として)数値を取得し、その数値に対してすべてのコマンドを実行し、結果を出力します。

コマンドは区切り文字,(コンマ+スペース)で区切られます。有効なコマンドは次のとおりです#負でない整数を表すことに注意してください)

  • add #/ subtract #-アキュムレーターから値を加算/減算します。
  • divide by #/ multiply by #- floordiv指定された値によって乗算/アキュムレータ。
  • subtract from #-に似てsubtractいますが、acc = # - acc代わりにacc = acc - #
  • repeat-最後のコマンドを再度実行してください。これを最初のコマンドにすることはできませんが、複数の連続した繰り返しをサポートする必要があります。

チャレンジ

あなたの仕事は、入力として有効なWordMathスクリプトを取り、プログラムや関数を作成することです transpilesあなたのコードが入っている同じ言語で-有効なフルプログラムにそれを。

たとえば、私のコードがPython 2であり、スクリプトが次の場合:

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

出力されるプログラムは次のとおりです。

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

または、代わりに:

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

限りそのまま完全なプログラムからの入力を受け取りSTDINにして印刷STDOUT、または言語の最寄りの当量です。


ルール

  • 元のプログラムは、入力が常に有効なWordMathスクリプトであると想定する場合があります。
  • トランスコンパイルされたプログラムは、0による除算などの数学的なエラーを処理する必要はありません。
  • トランスコンパイルされたプログラムは、入力があなたの言語の標準整数範囲内の有効な符号付き整数を表すと仮定するかもしれません。
  • これはであるため、最短のソリューション(バイト単位)が優先されます。
  • 元のプログラムのバイトカウントのみが重要です-出力されるコードは必要なだけ長くすることができます!

サンプルスクリプト

例1:

Think of a number. 

入力を行い、何もせずに表示する:WordMathのcatプログラム。

例2:

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

「分割」はので、このプログラムのために、床部門であることを忘れないでください6 -> 8、と29 -> 4

例3:

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

拡張猫プログラム!

例4:

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

数を取り、3を引きます。


連続した繰り返しをサポートする必要がありますか?
darrylyeo

1
それが言語のデフォルト型である場合/整数をサポートしていない場合、フロートを使用できますか?
レイナーP.

@RainerP。言語は、整数/整数の除算をサポートしていない場合にのみ
FlipTack

1
期待される結果は-5/3何ですか?0負の無限大に向かって、または負の無限大に向かって丸めますか?
マーティンエンダー

1
@MartinEnder フロア除算なので負の無限大に丸めますが、あなたの言語が整数除算を0に向けて実装している場合でも問題ありません。
FlipTack 16

回答:


6

05AB1E59 56 54 52バイト

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

オンラインでお試しください!

その後、私の脳は地獄のように痛い... 05AB1Eコードで次のように出力されます。

  • Think of a Number 暗黙的な入力のために削除されます。
  • Subtract From #変換先#s-(スワップabて操作を実行)。
  • Subtract #に変換し#-ます。
  • Add #に変換し#+ます。
  • Multiply by #に変換し#*ます。
  • Divide by #に変換し#/ます。
  • Repeat レジスタに最後に保存されたものをすべて取得し、連結します。

説明:

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

例:

入力:

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

出力:

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

10の入力で解決策を試してください。

オンラインでお試しください!

グーグルで見る:

googleに入力した同じ式へのリンクを次に示します。


13

Cプリプロセッサ、362バイト

私はほとんどCプリプロセッサでこれを動作させましたが、繰り返しコマンドは実装するのが非常に難しいことがわかりました。そこで、代わりにプリプロセッサを使用して入力を配列に変換し、それをいくつかの追加コードで解釈します。

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

入力は「input.wm」で提供するか、その行のソースにダンプする必要があります。そのバイトをカウントに含めたのは、チャレンジのルールに少しハックがかかっており、わずかに矛盾していることがわかったためです。

とにかく、WordMathソースをinput.wmにダンプすると、コンパイラはそれを見つけることができるので、WordMathソースが実行する実行可能ファイルを生成するための警告とともに、これをそのままコンパイルできるはずです。


2
注:残念ながら、繰り返しで終了すると、一部のコンパイラでは失敗します。これは、彼らが0の後にスペースを投げて、それから迷走期間を見て、それをどうするかわからないからです。
ラムダベータ16

賢い、私は感銘を受けました。

7

網膜、170バイト

誰がこれを見たくないのか?!

Retinaソリューションを見るのがどれほど素晴らしいかを考えて、すぐに作成することにしました。たった1時間でした。いつものように、バイトカウントは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

オンラインで試す

出力には、結果のプログラムをテストするときにコピーすべきではない末尾の改行があります。Retinaの標準整数範囲(単項)はサポートしないため、プログラムはネガをサポートしません。

説明:

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

数学プログラム:

追加:

1の数を先頭に追加します。5を追加:

^
1111

減算:

最初から1の数を削除します。減算5:

^11111

引き算:

入力1sをxsに置き換えます。固定数の横に置きます。繰り返し削除しx1ます。10を引く:

1
x
$
1111111111
+`x1

乗算:

すべて1を特定の数に置き換えます。3で乗算します。

1
111

除算:

これは整数除算に Retinaプログラムを使用します。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
$*

これがどのように機能するのかわからない。減算コマンドで入力しようとしても、結果が壊れます(出力に改行がありますか?)。また、これが負の入力または負の中間結果をどのように処理するかわかりません。
マーティンエンダー

@MartinEnderこの単純化されたプログラムが出力に2つの値を与える理由を説明すると、減算を修正できます。retina.tryitonline.net/#code=JArCtjE&input=dGVzdAo
mbomb007 16

$文字列の最後または末尾の改行の前で一致するため。\z前者だけが必要な場合に必要です。
マーティンエンダー

4

GNU awk、139バイト

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

呼び出し:

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

テストケース:

$> 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バイト

もちろん、機能的なプログラマーは、プログラムを表す文字列よりも関数を返すことを好むでしょうが、ここでは次のようにします。

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

注釈:常にゼロを追加することから始めます。さもないと、単純なWordMathプログラムのトランスパイレーションでreadは、使用される型を推測するのに十分な情報が得られません。subtract from nとして実装できます(n-)((-)n)、より均一にするために使用します。以下の場合、subtract nIコピーしsubtract、私はそれを記述する必要はありませんので、入力から、私は最後に不足しているスペースを補償する必要があります。repeatデフォルトの操作として使用されます。空の最初の前の操作とともに、これにより最初の4つの単語を簡単に無視できます。

使用例:

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

他の例では、次の結果が得られます。

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

好奇心が強いのですが、文字列の代わりに返す関数をどのように生成しますか?
チョイス

関数型プログラミング言語では、関数の作成と作成は文字列の作成と追加と同じくらい簡単です。hのようなものでh s n r|x<-s.read.init$n=x%r.x、最初の引数で次のような関数と呼ばれるかもしれませんh(+)n r(そしてflip正しい演算子の順序を得るためにどこかにある必要があります)、基本ケースは_%_=idです。主な機能は、すべての定型文を避けることができますt l=id%words l。-カリー化のおかげで、通訳と見なされる可能性があり、そのアイデアはより簡単かつ/またはより短い解決策につながる可能性があります。
クリスチャンシーバーズ

4

パイソン2、263の 258 260 221バイト

これはおそらくもっと短いかもしれません。

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

オンラインで試す

//代わりに使用します/。なぜなら、最後の命令は.末尾にaを持ち、任意の数を浮動小数点数にするからです。したがって、除算の一貫性を保つために、整数除算を使用します。

テストケースの出力:

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

あなたがその大きなブロックに変更した場合ifのためのo(私は動作するはずだと思うもの)、次へを:o=[[o+[['+-'['s'in c],'//']['v'in c],'*']['m'in c]+n,n+'-'+o]['f'in c],'input()']['T'in c]あなたは224にそれを得ることができます
カーデ

@Kadeええ、それはまだ読みやすいです。それはできません。
mbomb007 16

@Cyoceいいえ、ラムダを呼び出すという行為は、おそらくそれが節約する以上の費用がかかるでしょう。支払いごとに4または5バイトを節約する必要があります。
mbomb007 16

4

Befunge、342の 305バイト

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

オンラインでお試しください!

出力

生成するコードは&(入力値)コマンドで始まり、.(出力値)および@(終了)コマンドで終わります。その間に、の形式のさまざまな計算が<number><operation>あり、操作+(加算)、-(減算)、/(除算)、*(乗算)、および\-(減算)になります。

そのニーズよりも大きなものを手動で計算するのでBefungeのみ、範囲0〜9の数値リテラルをサポートしているので、それ自体は、少し複雑です。すでに文字ごとに数字を読み取っているので、各数字が読み取られると単純に数字が増えていきます。たとえば、123は155+*2+55+*3+、つまりになり(((1 * 10) + 2) * 10) + 3ます。

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

説明

Befungeには文字列を操作する機能がないため、解析のほとんどは文字をカウントすることで処理されます。最初の18文字をスキップすることから始めます。これにより、数字句(およびコンマまたはピリオド)を考えることができます。次に、次の文字が改行またはEOFの形式である場合、出力ルーチンに直接進みます。そうでない場合は、コマンドリストを探し続けます。

コマンドを解析するには、数字または区切り文字に達するまで文字を数え続けます。区切り文字の場合、特殊なケースとして処理する繰り返しコマンドである必要があります。それが数字の場合、出力バッファーに追加し、さらに数字を探し続けます。数字が出力されるたびに、接頭辞55+*(これまでの合計に10を掛ける)と接尾辞+(合計に加算する)を付けます。数字が完成したら、コマンド文字を追加します。

コマンドがどのように決定されるかについては、我々は最初の桁に文字のカウントを取るには、のために7を法追加するために、(次のスペースを含む)、これは4で引くことが2だため、除算、それがために、3だ乗算によって、それは5です、そして用から差し引くことの0 から差し引くことが必要であるため、ほとんどの追加処理が必要な\-コマンドのコンボを、他の人がちょうどテーブルで適切なコマンド文字を検索するために彼らの値を使用します。

このプロセスは、コマンドごとに繰り返され、出力を8行目の事前に構築された文字列に構築します。追加のコマンドが追加されるたびに、文字列に閉じ引用符を追加して、常に適切に終了するようにします。その後、最終的に入力の最後に到達したら、この文字列を単に「実行」してスタックにプッシュし、それに続いて標準出力シーケンスを使用してすべてを書き出します。


3

JavaScript(ES6)、163バイト

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

それを試してみてください:

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バイト

@ Flp.Tkcのように連続して複数の繰り返しを実行する機能を追加しましたが、バイトカウントを減らすことができるのに十分なバイトを使い果たしました。

: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

印刷できない文字:

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

テストケースの出力:

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

これは、複数の連続した繰り返しでは機能しないようです。
FlipTack 16

@ Flp.Tkc修正、ありがとう!私は以前に気づかなかった。
nmjcman101 16

2

lex、246バイト

%{
#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はCをターゲットとするため、Cコンパイラはそれを実行可能なものにコンパイルする必要があります。レクサーライブラリ(ll)もリンクする必要があります。これにより、バイトペナルティが追加される可能性がありますが、その場合、バイト数はわかりません。

プログラムは、変換されたwordmath式を評価するlexプログラム(仕様ごと)を出力します。コードの間%{%}だけ「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 */

2 %%行の間は正規表現/アクション部分です。一致する最初のルールはT( "Think ...")で、プリアンブルを構築します(lexプログラムは少なくともルールセクションを含む必要があり、yytext最後に一致するテキストであるため、ルールは基本的にアキュムレータにユーザーの入力をシードします。 )。

プログラムが一致していることを除いて、すべての入力、及び他のルールが(破棄しadfrアップにre)一意であることが可能な限り最小のAマッチなどでwordmath発現句を処理します。これらのほとんどではc、式infixに設定されます。これは、呼び出されたnときOに読み込まれる最後の整数と連結されます(たとえば、「add 9」を読み込むとinfixが+=vに設定され9、呼び出しがOに出力されますn+=9;) 。(興味深い点は、「8から減算」sによりfrルールとルールの両方が一致することですが、O番号でのみ呼び出されるため、適切なルールn=-n+8;が出力を取得する唯一の式です)。re「繰り返し」のルールは単に呼び出すO再び、最後に作成された式を出力します(そして、後続の一致がclobber yytextになるので、「繰り返し」をサポートする[0-9]+ことが、ルールの整数変換が必要な理由です)。最後に、ピリオドによりプログラムトレーラーが出力されます。これにより、アキュムレータ%%が出力され、出力lexプログラムの終了を示すペアで終了します。

注: メインのトランスパイラープログラムも出力プログラムも終了しません。入力をパイピングするか、EOF(ctrl-D)を提供します。最初の入力後に終了が必要な場合は、exit()を追加できます。

ビルド/実行するには:

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
%

テスト1:

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

テスト2:

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

テスト3:

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

テスト4:

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

2

Pyth、69 67バイト

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

aの入力を受け取り"quoted string"、結果を出力するプログラム。

テストスイート

使い方

Pythにはプレフィックス演算子があるため、基本的な算術演算はを使用して実行され(operator)(operand1)(operand2)、事前に初期化された変数Qが入力を提供します。したがって、トランスワードされたWordMathプログラムは、string 'Q'で始まり、各ステージで演算子を先頭に追加し、必要に応じてオペランドを先頭または末尾に追加することで構築されます。

J\QJ変換されたプログラム文字列を文字列に設定します'Q'

tcQ\, 入力をコンマで分割し、最初の要素( ' Think of a number')を破棄します

V そのためNに:

  • Iq@N1\r の文字N[1]'r'(繰り返し)の場合:
    • =NZセットNZ(前の値Nforループの終了時に設定)
  • x"asdm"@N1N[1]in のインデックスを見つける"asdm"(加算、減算、除算、乗算)
  • @"+-/*" にインデックスを"+-/*"付け、必要な演算子を指定します
  • ,J-eCN)\.2要素のリスト[J, -eCN)\.]を生成します。2番目の要素は、N空白文字の分割の最後の要素で、任意の'.'文字が削除されています(オペランド)
  • qh@cN)1\fN空白 の分割の2番目の要素の最初の文字が'f'(から減算)の場合:
    • .> 2要素リストの要素を交換します
  • + 演算子と2要素のリストを1つのリストにマージします
  • =JjdJスペースで結合されたものに 設定
  • =ZN 設定するZにはN

J 印刷する J


ナイスアンサーマン... 05AB1Eで試してみようと思いました。これは予想以上に威圧的でした。
魔法のタコUr

2

ピップ、58バイト

残念なことに、その逆減算演算子はまだ実装していません。

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

このプログラムは、標準入力からWordMathスクリプトを取得し、Pipコードを標準出力に出力します。同様に、出力されるコードはstdinから数値を取得し、結果をstdoutに出力します。オンラインでお試しください!

戦略

このような入力の場合:

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

次のような出力が必要です。

YqYy*3Yy+1

次のように機能します。

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 +説明

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

プログラムの基本構造はで{...}Mq^k、これは(コンマスペース)qk(標準入力の行)を分割Mし、各要素に関数を追加します。

関数内で、repeatケースの処理から始めます。Pipでの最短テストはsNa(コマンドにスペースがあります)のようです。もしそうなら、使用したいa; そうでない場合は、p前のコマンドを保存するを使用します。その値ap(また)に割り当てます。

戻り値には、リストを使用します。リストのデフォルトの出力形式はすべてを連結するためです。結果は常にで始まりYます。次に、操作用のルックアップテーブルが必要です。

長ことを観察add (4)、subtract (9)、divide by (10)、multiply by (12)、及びsubtract from (14)は全て異なっています。さらに、mod 7を使用した場合でもそれらが異なることを確認します。したがって、これらを使用して7要素リスト(5つのコードスニペットと2つのプレースホルダーを含む)にインデックスを付け、各WordMathコマンドを適切なPipコード(番号単に最後に連結できます):

  • 0: ()-y+subtract from
  • 1:プレースホルダー
  • 2: ()y-subtract
  • 3: ()y//divide by
  • 4: ()y+add
  • 5: ()y*multiply by
  • 6:プレースホルダー

インデックスについては、正規表現を使用して、コマンドの最初の数字のインデックスを取得しますa@?`\d`。またy、将来の使用のために正規表現をヤンクします。ルックアップテーブルは、文字列"-y+ y- y// y+ y* "s(スペース)で分割することにより生成されます。

コードに変換する必要がある最初のエントリを処理する必要がありますYqThink of a number数字が含まれていないため、@?演算子はnilを返します。ルックアップテーブルへのインデックスとしてnilを使用すると、nilも返されます。Nilは偽であるため、この場合の操作の代わり|'qにuse qを追加するだけです。

返されるリストの最後の要素は、数値そのものです。これを取得しa@yます(先ほどヤンクした数字の正規表現のコマンドですべての一致を検索します)。これは数字のリストを返しますが、出力時にすべてのリストが連結されるため、これも問題ではありません。最初のエントリでは、a@y数字と一致せず、空のリストが生成されますが、出力には何も追加されません。

例えば

入力あり

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

マップ式はリストを提供します

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

連結すると、出力します

YqY-y+20Yy+2Yy+2

2

パイソン2154の 153 146バイト

修正し、プロセスで数バイトも保存しました。^ __ ^

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"

オンラインでお試しください!

私のピップの答えと同じ戦略に基づいています。Python固有の機能:

  • Think of そして、終了.は、分割する前に文字列から削除されます(input()[9:-1])。この期間は厄介すぎて、メインループで処理できませんでした。最初の9文字を削除すると、別の理由で役立ちます(以下を参照)。
  • 数字を正規表現で検索して各コマンドの長さを取得する代わりに(Pythonでは高価なためimport re)、rfind(" ")コマンドの最後のスペースを見つけるために使用します。これを使用して、repeatケースを確認することもできます。
  • PythonにはPipの循環インデックスがありません。そのため、インデックスmod 7を明示的に取得する必要があります。一方、これは、インデックスmod 7が6になることはないため、ルックアップテーブルの最後のダミー値を削除できることを意味します。
  • 最初の「コマンド」a numberはで、このスペースのインデックスは1です。このインデックスは、ルックアップテーブルの他の穴を埋めるのに便利です。メインループで入力ステージを処理する際のもう1つの問題は、その+c[s:]部分でしたx=input() number。その問題を解決するには、我々の文字列-乗算することによりc[0]<"a"1ここですべての定期的なコマンドのためのcスペースから始まりますが、0初期のためにa number

1

WinDbg、449 388バイト

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バイト

LambdaBetaのの使用に触発されました#define。このアプローチの修正WordMath構文はわずかに(,及び.スペース区切り言い換えると同様である必要があり、,従っていないrepeat)、および修飾WordMath構文が有効WinDbgのコードであるように、エイリアスを作成します。最後の行は、入力を修正された構文に変換することにより、質問が尋ね、変換することを行います。

入力は、メモリアドレスに文字列を設定し、$t0そのアドレスに擬似レジスタを設定することにより行われます。注:これはintat を上書きする0x2000000ため、そこで文字列を開始すると、部分的に上書きされます。$t0上書きされます。

エイリアスを作成するため、このコードが文字列を設定する前に実行したか後に実行したかに応じて、出力コードは異なります(エイリアスの有無)。残念ながら、空白で区切られずにエイリアスを適切に展開する方法が見つかりませんでした(つまり、WordMathスクリプトは、最初に変換されずに直接実行されることはできませんでした)。

使い方:

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

このコードを1回実行する前に文字列を入力するサンプル出力(結果のプログラムは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

このコードが1回実行された後に文字列を入力するサンプル出力(結果のプログラムがきれいではないように文字列を入力するときにエイリアスが展開されます):

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

わずかに変更されたWordMath構文を使用した、さらにいくつかのサンプル出力:

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バイト

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

説明:

// 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)")
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.