六角形、271バイト
六角形の通訳の最初の3%を紹介します...
|./...\..._..>}{<$}=<;>'<..../;<_'\{*46\..8._~;/;{{;<..|M..'{.>{{=.<.).|.."~....._.>(=</.\=\'$/}{<}.\../>../..._>../_....@/{$|....>...</..~\.>,<$/'";{}({/>-'(<\=&\><${~-"~<$)<....'.>=&'*){=&')&}\'\'2"'23}}_}&<_3.>.'*)'-<>{=/{\*={(&)'){\$<....={\>}}}\&32'-<=._.)}=)+'_+'&<
オンラインでお試しください!自身で実行することもできますが、約5〜10秒かかります。
原則として、これはサイド長9(217以下のスコア)に収まるかもしれません。これはこれが201コマンドのみを使用し、最初に(サイド長30で)書いた非ゴルフバージョンが178コマンドしか必要としないためです。ただし、すべてを実際に適合させるには永遠にかかると確信しているので、実際に試してみるかどうかはわかりません。
最後の1行または2行の使用を避けることで、サイズ10でこれを少しゴルフすることも可能です。これにより、後続のノーオペレーションを省略できますが、最初のパスの1つとして大幅な書き換えが必要になります。結合は左下隅を利用します。
説明
コードを展開し、制御フローパスに注釈を付けることから始めましょう。
それはまだかなり厄介ですので、ここに私が最初に書いた「改変されていない」コードの同じ図があります(実際、これはサイドレングス20であり、もともとサイドレングス30でコードを書きましたが、それはあまりにもまばらでした可読性はまったく向上しないので、サイズを少し合理化するために少し圧縮しました):
クリックして拡大版をご覧ください。
いくつかの非常に小さな詳細を除き、色はまったく同じですが、非制御フローコマンドもまったく同じです。それで、私はこれが非ゴルフバージョンに基づいてどのように機能するかを説明します、そしてあなたが本当にゴルフされたものがどのように動作するか知りたいなら、あなたは大きな六角形のどの部分に対応する部分を確認できます。(唯一の落とし穴は、実際のコードが左に行く右隅から始まるように、ゴルフのコードが鏡で始まることです。)
基本的なアルゴリズムは、私のCJamの回答とほぼ同じです。2つの違いがあります。
- 中心化された六角形の方程式を解く代わりに、入力の長さ以上になるまで連続した中心化された六角形の数を計算します。これは、Hexagonyには平方根を計算する簡単な方法がないためです。
- 入力に何も入力せずにすぐにパディングする代わりに、入力のコマンドがすでに使い果たされているかどうかを後で確認し、ある場合は
.
代わりにaを出力します。
つまり、基本的な考え方は次のように要約されます。
- 入力文字列の長さを計算しながら読み取り、保存します。
- 入力全体を保持できる最小の辺の長さ
N
(および対応する中央の六角形の数値hex(N)
)を見つけます。
- 直径を計算し
2N-1
ます。
- 行ごとに、インデントとセル数(合計
2N-1
)を計算します。インデントを印刷し、セルを印刷します(.
入力がすでに使い果たされている場合に使用)、改行を印刷します。
何もしないので、実際のコードは左隅から始まります($
を飛び越える>
ので、実際,
には暗い灰色のパスから始まります)。
初期メモリグリッドは次のとおりです。
そのため、メモリポインターはinputというラベルが付いたエッジから始まり、北を指します。,
STDINからバイトを読み取るか、-1
そのエッジにEOFがヒットした場合。したがって、<
直後はすべての入力を読んだかどうかの条件です。とりあえず入力ループのままにしておきましょう。次に実行するコードは
{&32'-
これは、スペースとラベル付けされたエッジに32を書き込み、それからdiffとラベル付けされたエッジの入力値からそれを減算します。入力には印刷可能なASCIIのみが含まれることが保証されているため、これが負になることはありません。入力がスペースの場合、ゼロになります。(Timwiが指摘しているように、入力に改行またはタブが含まれる場合でもこれは機能しますが、32未満の文字コードを持つ他のすべての印刷不能文字も削除します。)その場合、<
命令ポインター(IP)そして明るい灰色のパスが取られます。そのパスは単にMPの位置をリセットし{=
、次の文字を読み取ります。したがって、スペースはスキップされます。それ以外の場合、文字がスペースではない場合、実行します
=}}})&'+'+)=}
これはまず、diffエッジの反対側まで、長さエッジを六角形の周りに移動します。反対側からそれをコピー値の長さにエッジ長辺、及び増分それと。なぜこれが理にかなっているのかはすぐにわかるでしょう。最後に、新しいエッジを移動します:=}}}
)&'+'+)
=}
(特定のエッジ値は、チャレンジで指定された最後のテストケースのものです。)この時点で、ループが繰り返されますが、すべてが1つの六角形から北東にシフトされます。したがって、別の文字を読み取った後、次のようになります。
北東の対角線に沿って入力(マイナススペース)を徐々に書き込み、文字を1つおきのエッジに書き込み、その文字までの長さをlengthというラベルの付いたエッジと平行に保存していることがわかります。
入力ループを完了すると、メモリは次のようになります(次の部分のいくつかの新しいエッジにラベルを付けています)。
%
私たちが読んで最後の文字である、29
我々は読ん非空白文字の数です。次に、六角形の辺の長さを見つけたいと思います。まず、濃い緑/灰色のパスにいくつかの線形初期化コードがあります。
=&''3{
ここで=&
、長さ(この例では29)をlengthというラベルの付いたエッジにコピーします。次に''3
、3というラベルの付いたエッジに移動し、その値を設定します3
(計算で定数として必要なだけです)。最後{
に、N(N-1)というラベルの付いたエッジに移動します。
次に、青いループに入ります。このループはN
(Nのラベルが付いたセルに格納されます)インクリメントしてから、中心の六角形の数値を計算し、入力長から減算します。それを行う線形コードは次のとおりです。
{)')&({=*'*)'-
ここで、Nに{)
移動し、インクリメントします。N-1というラベルの付いたエッジに移動し、そこでコピーしてデクリメントします。N(N-1)の積を計算します。これに定数を乗算し、hex(N)というラベルの付いたエッジで結果をインクリメントします。予想どおり、これはN番目の中央六角形番号です。最後に、その長さと入力長の差を計算します。結果が正の場合、辺の長さはまだ十分に大きくなく、ループが繰り返されます(MPをN(N-1)とラベル付けされたエッジに戻します)。')&(
N
{=*
'*)
3
'-
}}
辺の長さが十分に大きくなると、差はゼロまたは負になり、次のようになります。
最初に、出力ループに必要な初期化を行う非常に長い線形の緑のパスがあります。
{=&}}}32'"2'=&'*){=&')&}}
まず{=&
、差分エッジの結果を長さエッジにコピーすることから始めます。これは、後で非正の値が必要になるためです。space}}}32
というラベルの付いたエッジに32を書き込みます。diffの'"2
上のラベルのないエッジに定数2を書き込みます。同じラベルで2番目のエッジにコピーします。これを2で乗算し、インクリメントして、上部の2N-1というラベルの付いたエッジで正しい値を取得します。これは六角形の直径です。2N-1というラベルの付いたもう一方の端に直径をコピーします。最後に、上部の2N-1というラベルの付いたエッジに戻ります。'=&
N-1
'*)
{=&')&
}}
エッジにラベルを付け直しましょう:
現在のエッジ(六角形の直径を保持している)を使用して、出力のラインを反復処理します。indentというラベルの付いたエッジは、現在の行に必要なスペースの数を計算します。エッジのラベルが付いたセルは、現在の行のセルの数を反復処理するために使用されます。
indentを計算するピンクのパスになりました。行反復子を('-
デクリメントし、N-1から(インデントエッジに)減算します。コード内の短い青/灰色の分岐は、結果のモジュラスを計算するだけです(負またはゼロの場合は値を否定し、正の場合は何も起こりません)。ピンクのパスの残りの部分は、セルの端まで直径からインデントを差し引いてから、インデントの端に戻ります。~
"-~{
汚れた黄色のパスがインデントを印刷するようになりました。ループの内容は本当にただ
'";{}(
どこ'"
に移動スペースエッジは、;
それを印刷し、{}
移動しに戻りインデント及び(
それをデクリメントします。
これが完了すると、(2番目の)濃い灰色のパスが印刷する次の文字を検索します。=}
(上手段、位置に移動した細胞の縁、南を指します)。次に{}
、保存された文字列の最後に到達するまで、南西の方向に2つのエッジを単純に下に移動する非常にタイトなループがあります。
EOFの 1つのエッジにラベルを付け直したことに注意してください。。この文字を処理したら{}
、次の反復ではなくここでループが終了するように、そのエッジを負にします。
コードでは、暗い灰色のパスの最後にあり'
、入力文字に1ステップ戻ります。状況が最後の2つの図の1つである場合(つまり、まだ印刷していない入力から文字が残っている場合)、緑のパス(下の緑、緑が苦手な人、青)。これはかなり簡単です;
。キャラクター自体を印刷します。'
対応するスペースエッジに移動します。スペースエッジは、以前の32を保持し、;
そのスペースを印刷します。次に{~
、EOFを作成しますか?次の反復で負の値を指定'
すると、1つ前のステップに戻り、別のタイト}{
ループで文字列の北西端に戻ることができます。長さで終わるセル(hex(N)の下の非正のセル。最後}
にセルの端に戻ります。
すでに入力を使い果たしている場合、EOFを検索するループは?実際にここで終了します:
その場合'
、長さのセルに移動し、代わりに水色(上部)のパスを使用します。このブランチのコードは線形です:
{*46;{{;{{=
{*46;
標識されていないエッジに46を書き込む無OP及び印刷それ(すなわち、A期間)。次に{{;
、スペースの端に移動して印刷します。{{=
移動するに戻りセル次の反復のためのエッジ。
この時点で、パスは結合し(
直され、セルの端が減ります。イテレータがまだゼロでない場合、ライトグレーのパスを使用します。これは単にMPの方向を反転させ、=
次に印刷する次の文字を探します。
そうでない場合、現在の行の終わりに到達し、IPは代わりに紫色のパスを取ります。これは、その時点でのメモリグリッドの外観です。
紫色のパスには次のものが含まれます。
=M8;~'"=
=
再びMPの方向を反転させます。is の文字コードが現在の値に追加されるため、M8
値をセットに設定します。これはたまたまなので、で印刷すると、改行が表示されます。次に、エッジを再びネガティブにし、ラインエッジに戻り、MPをもう一度反転します。778
M
77
10 (mod 256)
;
~
'"
=
今ならばラインのエッジがゼロである、我々は完了です。IPは(非常に短い)赤いパスを取り@
、プログラムを終了します。そうでない場合は、ピンクのパスにループバックする紫色のパスに進み、別の行を印刷します。
TimwiのHexagonyColorerで作成された制御フロー図。Esoteric IDEのビジュアルデバッガで作成されたメモリダイアグラム。
abc`defg
実際にpastebin.com/ZrdJmHiR