Prindeal(顕著PRIN-ディー-ALは)新しいある難解:4つのつのみコマンド有するプログラミング言語PR INTを、で crement、デ crement、そしてら IAS。4つのコマンドを巧みに組み合わせることにより、Prindealで複雑な数学演算を最小限に抑えることができます。
このゴルフのチャレンジの課題は、Prindealコードを実行できる最短のプログラムを作成することです。
仕様は長いですが、できる限り明確にしようとしました。Prindealを学習するための努力をすれば、非常にエレガントであることがわかります。
Prindealの解釈
前処理
Prindealプログラムを解釈する前に、これらのことを次の順序で削除する必要があります。
#
記号の後にある行の最後までのすべてと、#
それ自体。(これらはコメントです。)- 任意の行の末尾の空白。
- 完全に空の行。
たとえば、Prindealプログラム
p cat #The next line has 7 trailing spaces.
p dog
#p mouse
前処理されます
p cat
p dog
ここからは、この前処理ステップが完了したと仮定します。
変数
変数の使用方法を示す前に、変数をすばやく定義する必要があります。
変数(および変数への参照)は、Prindealコマンドの引数に渡されるものです。変数は常にグローバルであるため、変数の変更は、それらがどこで発生しても、どこにでも反映されます。
各変数は、負でない任意精度の整数(0、1、2、3、...)を保持します。変数は事前に初期化する必要はありません-変数は、最初に使用または呼び出されるときに常に値0で始まります。
変数名は、数字[a-zA-Z_][0-9a-zA-Z_]*
と正規表現で始まらない、英数字とアンダースコアの空でない文字列です。これらは大文字と小文字が区別されるためspiny_lumpsuck3r
、Spiny_lumpsuck3r
異なる変数です。
実行
Prindealは命令型プログラミング言語です。Prindealプログラムが実行されると、ステートメントが上から下の順に実行され、プログラムが終了します。
Prindealプログラムのインデントされていない行はすべて、引数を取る場合と受け取らない場合がある単一のコマンドの実行を伴うステートメントです。
インデントされた行は、エイリアスコマンドの後にのみ発生します。具体的には、すべてのエイリアスコマンドの後に、単一のスペースでインデントされた正確に3行が発生し 、その一部と見なされます。したがって、別名ステートメントは実際には4行の長さです。(1行にすることもできますが、4行は読みやすいだけです。)
非エイリアスステートメント
aliasを除き、Prindealプログラムのすべてのステートメントの形式は次のとおりです。
[command name] [argument 1] [argument 2] [argument 3] ...
任意の数の引数がある場合があります(まったくない場合もあります)。各引数は常に変数または(エイリアスについて説明するときに説明します)変数への参照です。
実行が完了すると、エラーが発生したかどうかに応じて、各ステートメントに失敗または成功のフラグが立てられます。(これは、aliasの使用に取り掛かる場合にのみ本当に重要です。)
組み込みのprint、increment、およびdecrementは、上記の形式のステートメントです。彼らがすることは次のとおりです。
printにはコマンド名が
p
あり、1つの引数を取ります。渡された変数の名前とその値(10進数)を "="で区切り、次に改行を出力します。常に成功としてフラグが付けられます。たとえば、Prindealプログラム
p _MyVariable_321 p screaming_hairy_armadillo
出力します
_MyVariable_321 = 0 screaming_hairy_armadillo = 0
すべての変数が0から始まるためです(等号の前後にスペースが必要です)。
incrementはコマンド名
i
を持ち、1つの引数を取ります。渡された変数の値を1増やします。常に成功のフラグが立てられます。たとえば、プログラム
i alpaca p alpaca i alpaca p alpaca
出力します
alpaca = 1 alpaca = 2
alpaca
以前にアクセスされたことがない場合でも、どのように0から1にインクリメントされたかに注意してください。デクリメントにはコマンド名が
d
あり、1つの引数を取ります。渡された変数がゼロ以外の場合、その値は1ずつ減分され、ステートメントに成功のフラグが立てられます。渡された変数が0の場合、何も実行されず、ステートメントに失敗のフラグが立てられます。たとえば、プログラム
i malamute p malamute d malamute #success p malamute d malamute #failure p malamute d akita #failure p akita
出力します
malamute = 1 malamute = 0 malamute = 0 akita = 0
値が0の変数をデクリメントすることが失敗を生成する唯一の方法であることに注意してください。
エイリアスステートメントとエイリアスコマンド
エイリアスコマンドは、特別な構文を持っており、新しいコマンドを定義するために使用することができますので、最も強力です。エイリアスコマンド名があるa
と、エイリアスの文の形式は次のとおりです。
a [name of new command]
[statement A]
[statement B]
[statement C]
ここで、それぞれ[statement X]
は非エイリアスステートメント、つまりの形式の何かを表します[command name] [argument 1] [argument 2] [argument 3] ...
。
エイリアスコマンドの名前[name of new command]
は[a-zA-Z_][0-9a-zA-Z_]*
、正規表現で数字で始まらない英数字とアンダースコアの空でない文字列です。
(これは変数と同じ名前のセットですが、エイリアス化されたコマンドと変数は異なる場所で使用されるものが異なります。変数はコマンドと同じ名前で、悪影響はありません。)
とき別名文が実行され、新しいコマンドは、元の4一緒に追加されp
i
d
a
たコマンド。新しいコマンドは[command name]
inステートメントとして使用でき、他の非エイリアスコマンドと同様に引数で呼び出すことができます。
エイリアス化されたコマンド名を持つステートメントが実行されると、元のエイリアスステートメントからさらに2つのステートメントが実行されます。
[statement A]
常に実行されています[statement B]
成功した場合[statement A]
に実行されます[statement C]
失敗した場合[statement A]
に実行されます
ステートメントA、B、およびCは常に遅延して実行されます。つまり、実行時にその場で評価されます。
実行が完了すると、エイリアス化されたコマンドには、ステートメントBまたはCのいずれか実行された方と同じ成功または失敗フラグが立てられます。(別名ステートメント自体は、その内部で発生することはできないため、フラグを立てる必要はありません。)
エイリアスの例1
変数を
frog
2回インクリメントする新しいコマンドが必要だとします。このエイリアスステートメントはそれを実現します:a increment_frog_twice i frog i frog d frog
ステートメントAは、(
i frog
)は、常に実行して、いつものようにフラグが設定され、成功 ステートメントB(これi frog
も常に実行される)と、変数はfrog
ので、2ずつ増えているincrement_frog_twice
コマンドはいつものようにフラグが立てられ、成功ステートメントBが常に実行されるためとBが常にあります成功。ステートメントC(d frog
)は実行されません。したがって、出力は
a increment_frog_twice i frog i frog d frog p frog increment_frog_twice p frog
だろう
frog = 0 frog = 2
この例を一般化して、エイリアス化されたコマンドに引数を与えることにより、任意の変数を2回インクリメントできるようにすることができます。
エイリアスステートメント内で、正の整数1、2、3などは、エイリアスコマンドに渡される1番目、2番目、3番目などの引数を表します。(これらの引数は、単純な変数または変数自体への参照である可能性があります。)これらの数値は、別名ステートメントのステートメントA、B、およびCの引数内にのみ表示できます。彼らが他の場所に現れるのは意味がありません。
エイリアスの例2
これは最後の例を一般化します-渡された変数は、渡された最初の引数への参照である
increment_twice
ため、2ずつ増加します1
。a increment_twice i 1 i 1 d 1 #never reached p toad increment_twice toad p toad
このプログラムの出力は次のようになります
toad = 0 toad = 2
次に、2つの引数を取り、
increment_twice
両方の引数を呼び出す別のコマンドをエイリアスできます。a increment_twice i 1 i 1 d 1 #never reached a increment_both_twice increment_twice 1 increment_twice 2 d 1 #never reached increment_both_twice platypus duck p platypus p duck
ここでの出力は次のようになります
platypus = 2 duck = 2
エイリアスされたコマンドは再帰的である可能性があることを理解することが重要です。たとえば、渡された変数を0に設定するコマンドを作成できます。
エイリアスの例3
この
set_to_zero
コマンドは1つの引数を取り、その変数を0に設定し、完了すると成功のフラグが立てられます。a set_to_zero d 1 set_to_zero 1 i _dummy_ i oryx i oryx i oryx p oryx set_to_zero oryx p oryx
このプログラムの出力は次のようになります
oryx = 3 oryx = 0
何が起こっているのかは、
set_to_zero oryx
実行されると、3から2にd 1
正常に減少oryx
し、その後set_to_zero 1
呼び出さset_to_zero oryx
れます。これは、再度呼び出すのと同じです。プロセスを繰り返すようになるまでには、d 1
ある故障、再帰を停止し、インクリメント_dummy_
して変数を成功が生成されます。
チャレンジ
上記のとおり、Prindealコードを実行できるプログラムを作成します。Prdinealコードを、stdin、コマンドライン、またはテキストファイルとして受け取ります。Prindealプログラムの出力をstdoutまたは使用している言語の最も近い代替物に出力します。
または、コードを文字列として受け取り、出力文字列を出力または返す関数を作成できます。
さらに、次のことを想定できます。
- 入力Prindealコードには、改行と印刷可能なASCIIのみが含まれ、オプションで空行で終了します。
- 入力コードは有効なPrindealになります-整形式で構文的に正しいです。
- コードを実行しても、無限ループや、定義されていないコマンドや指定されていない引数への無効な参照は生成されません。
- コマンド名は
p
、i
、d
、およびa
オーバーエイリアスされることはありません。(変数にこれらの名前がないと仮定することはできません。)
また、変数値が実際に任意精度の整数でない場合でも、約1000未満の数値のみがテストされるため、問題ではありません。また、言語に再帰制限(Pythonなど)がある場合でも、以下のテストプログラムが機能する限り、より複雑なPrindealプログラムが遭遇する可能性があります。
テストプログラム
これは、ダミー変数(_
慣例により開始)と多くのヘルパーエイリアスを使用して、加算、乗算、べき乗の演算を構築する大きなPrindealプログラムです。
#Command Definitions:
a s #flag as a success
i _
d _
d _
a f #flag as a failure
d _
d _
d _
a z #1 = zero
d 1
z 1
s
a n #1 = one
z 1
i 1
s
a move #2 += 1, 1 = zero
moveH 1 2
move 1 2
s
a moveH #move helper
d 1
i 2
f
a dupe #2 += 1, 3 += 1, 1 = zero
dupeH1 1 2 3
dupe 1 2 3
s
a dupeH1 #dupe helper
d 1
dupeH2 2 3
f
a dupeH2 #dupe helper
i 1
i 2
s
a copy #2 = 1
z 2
copyH 1 2
s
a copyH #copy helper
dupe 1 2 _copy
move _copy 1
s
a addTo #1 += 2
copy 2 _add
#testing comments #
move _add 1#in weird places # just because #
s
#it's a g##d idea
###
a add #1 = 2 + 3
#its a good idea
z 1
addH 1 2 3
s
##
#
a addH #add helper
#this is a comment
addTo 1 2 #as is this
addTo 1 3
s
a mul #1 = 2 * 3
mulH1 1 2
mulH2 1 3
s
a mulH1 #mul helper
z 1
copy 2 _mul
s
a mulH2 #mul helper
mulH3 1 2
mulH2 1 2
s
a mulH3 #mul helper
d _mul
addTo 1 2
f
a mulBy #1 *= 2
mul _mulBy 1 2
copy _mulBy 1
s
a pow #1 = 2^3
powH1 1 3
powH2 1 2
s
a powH1 #pow helper
n 1
copy 2 _pow
s
a powH2 #pow helper
powH3 1 2
powH2 1 2
s
a powH3 #pow helper
d _pow
mulBy 1 2
f
#Running Tests:
p A
p B
p C
n A #A = 1
n B #B = 1
add C A B #C = A + B = 1 + 1 = 2
p ____
p A
p B
p C
add B A C #B = A + C = 1 + 2 = 3
p ____
p A
p B
p C
mul d B C #d = B * C = 3 * 2 = 6
p ____
p d
mulBy d B #d = d * B = 6 * 3 = 18
p ____
p d
d A #A = A - 1 = 1 - 1 = 0
mulBy d A #d = d * A = 18 * 0 = 0
p ____
p d
pow A C B #A = C ^ B = 2 ^ 3 = 8
p ____
p A
p B
p C
pow A B C #A = B ^ C = 3 ^ 2 = 9
p ____
p A
p B
p C
pow C A B #C = A ^ B = 9 ^ 3 = 729
p ____
p A
p B
p C
(このコードで遊んでいる場合、同じ変数が引数として複数回与えられるとコマンドの多くが失敗することに注意してください。これは簡単に修正できますが、結果のコードは長くなります。)
Prindealインタープリターは、正確な出力を生成できるはずです。
A = 0
B = 0
C = 0
____ = 0
A = 1
B = 1
C = 2
____ = 0
A = 1
B = 3
C = 2
____ = 0
d = 6
____ = 0
d = 18
____ = 0
d = 0
____ = 0
A = 8
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 729
得点
バイト単位の最短コードが優先されます。Tiebreakerは以前の提出に進みます。
ブラウニーボーナス:Prindealでクールなプログラムを作成します。加算と乗算を実装しましたが、減算または除算はできますか?
p
、増分し、それからp p
、1を印刷するでしょうか?