Golfscript-12文字
{,1\{)*}/}:f
Golfscriptを始めよう-段階的要因
ここでは、golfscriptを学ぼうとしている人々のためのものです。前提条件は、golfscriptの基本的な理解と、golfscriptドキュメントを読む能力です。
そこで、新しいツールgolfscriptを試してみたいと思います。単純なものから始めるのは常に良いので、階乗から始めます。これは、単純な命令型擬似コードに基づいた最初の試みです。
# pseudocode: f(n){c=1;while(n>1){c*=n;n--};return c}
{:n;1:c;{n 1>}{n c*:c;n 1-:n;}while c}:f
空白は、golfscriptで使用されることはほとんどありません。空白を取り除く最も簡単なトリックは、異なる変数名を使用することです。すべてのトークンを変数として使用できます(構文ページを参照)。変数のような特殊文字があると便利なトークンが使用する|
、&
、?
コードの他の場所で使用され、一般的には何もありません- 。これらは常に単一文字のトークンとして解析されます。対照的に、次のような変数では、n
後にスタックに数値をプッシュするためのスペースが必要になります。数値は基本的に事前に初期化された変数です。
いつものように、最終結果に影響を与えずに変更できるステートメントがあります。golfscriptでは、すべてのものは除くtrueと評価され0
、[]
、""
、及び{}
(参照これを)。ここで、ループの終了条件を単純に変更できます{n}
(追加の時間をループし、n = 0で終了します)。
あらゆる言語のゴルフと同様に、利用可能な機能を知ることは役立ちます。幸いなことに、リストはgolfscriptの非常に短いものです。に変更1-
し(
て、別のキャラクターを保存できます。現在、コードは次のようになっています:(必要に応じて1
、|
ここではなく初期化を削除します)
{:n;1:|;{n}{n|*:|;n(:n;}while|}:f
スタックを適切に使用して最短のソリューションを取得することが重要です(練習練習)。一般的に、値がコードの小さなセグメントでのみ使用される場合、変数に保存する必要はないかもしれません。実行中の製品変数を削除し、単にスタックを使用するだけで、非常に多くのキャラクターを節約できます。
{:n;1{n}{n*n(:n;}while}:f
他に考えるべきことがあります。n
ループ本体の終わりでスタックから変数を削除しますが、その後すぐにプッシュします。実際、ループを開始する前に、スタックからも削除します。代わりにスタックに残しておく必要があり、ループ条件を空白のままにできます。
{1\:n{}{n*n(:n}while}:f
変数を完全に削除することもできます。これを行うには、常にスタックに変数を保持する必要があります。つまり、条件チェックの終了時にスタック上に変数のコピーが2つ必要なので、チェック後に失われないようにします。これは0
、ループの終了後にスタックに冗長性を持たせることを意味しますが、修正は簡単です。
これにより、最適なwhile
ループソリューションが実現します。
{1\{.}{.@*\(}while;}:f
今、私たちはまだこれを短くしたいです。明らかなターゲットは単語であるべきwhile
です。ドキュメントを見ると、実行可能な代替案が2つあります-unfoldとdoです。さまざまなルートを選択できる場合は、両方の利点を比較検討してください。展開は「かなりしばらくループ」であるため、推定として5文字while
を4 ずつに減らします/
。についてはdo
、while
3文字ずつカットし、2つのブロックをマージします。これにより、別の文字が1つまたは2つ保存されます。
実際には、do
ループを使用することには大きな欠点があります。本体が1回実行された後に条件チェックが行われるため、の値0
が間違っているため、ifステートメントが必要になる場合があります。展開の方が短いことを説明します(do
最後にいくつかのソリューションが提供されています)。試してみてください。すでに持っているコードは最小限の変更が必要です。
{1\{}{.@*\(}/;}:f
すばらしいです!現在、私たちのソリューションは非常に短く、ここで完了です。いや。これは17文字で、Jは12文字です。敗北を認めないでください!
今、あなたは考えています...再帰
再帰を使用すると、分岐構造を使用する必要があります。残念ながら、階乗は簡潔に再帰的に表現できるため、これは反復の実行可能な代替手段のように思えます。
# pseudocode: f(n){return n==0?n*f(n-1):1}
{:n{n.(f*}1if}:f # taking advantage of the tokeniser
まあそれは簡単でした-以前に再帰を試みた場合、while
ループの使用を見ていなかったかもしれません!それでも、私たちはわずか16文字です。
配列
配列は通常、2つの方法で作成されます- [
と]
文字を使用するか、,
関数を使用します。スタックの先頭に整数を指定して実行すると、,
arr [i] = iでその長さの配列を返します。
配列を反復処理するには、3つのオプションがあります。
{block}/
:プッシュ、ブロック、プッシュ、ブロック、...
{block}%
:[push、block、push、block、...](これにはいくつかのニュアンスがあります。たとえば、各プッシュの前に中間値がスタックから削除されます)
{block}*
:プッシュ、プッシュ、ブロック、プッシュ、ブロック、...
golfscriptドキュメントには{+}*
、配列の内容を合計するために使用する例があります。これ{*}*
は、配列の積を取得するために使用できることを示しています。
{,{*}*}:f
残念ながら、それはそれほど単純ではありません。すべての要素が([0 1 2]
ではなく[1 2 3]
)1つずれています。{)}%
この問題を修正するために使用できます。
{,{)}%{*}*}:f
よくない。これはゼロを正しく処理しません。これを修正するために(n + 1)!/(n + 1)を計算できますが、コストがかかりすぎます。
{).,{)}%{*}*\/}:f
また、n = 1と同じバケットでn = 0を処理することもできます。これは実際には非常に短いので、できる限り短い時間を試してみてください。
7文字でソートするのはあまり良くありません:[1\]$1=
。このソート手法には、数字に境界を課すなどの便利な目的があることに注意してください(例: `[0 \ 100] $ 1 =)
。3文字のみの勝者は次のとおりです。
同じブロックでインクリメントと乗算を行いたい場合、配列内のすべての要素を反復処理する必要があります。配列を構築していないので、これはを使用する必要があることを意味します{)*}/
。これにより、factorialの最短のgolfscript実装が実現します。12文字の長さで、これはJと結び付けられます!
{,1\{)*}/}:f
ボーナスソリューション
ループの簡単なif
ソリューションから始めdo
ます。
{.{1\{.@*\(.}do;}{)}if}:f
これからさらにいくつかを絞ることができます。少し複雑なので、これらが機能することを自分で納得させる必要があります。これらをすべて理解してください。
{1\.!!{{.@*\(.}do}*+}:f
{.!{1\{.@*\(.}do}or+}:f
{.{1\{.@*\(.}do}1if+}:f
より良い代替方法は、(n + 1)!/(n + 1)を計算するif
ことです。これにより、構造が不要になります。
{).1\{.@*\(.}do;\/}:f
しかし、do
ここでの最短の解決策は、0から1にマップするのに数文字を必要とし、他のすべてをそれ自体にマップするため、分岐は必要ありません。この種の最適化は、見落としがちです。
{.!+1\{.@*\(.}do;}:f
興味のある方のために、上記と同じ長さのいくつかの代替再帰ソリューションがここに提供されています。
{.!{.)f*0}or+}:f
{.{.)f*0}1if+}:f
{.{.(f*}{)}if}:f
*注:この投稿のコードの多くは実際にはテストしていませんので、エラーがあればお知らせください。