CJam、139バイト
まあ、これは何かを達成するために何時間もかかった。CJamコードを積極的に最適化するのにかかる時間は、コードのサイズに関してO(n)よりも大きいように感じます...
オンラインで試すことができますが、6パス以上の最適なパスがある入力については、おそらくより高速なインタープリターを使用してオフラインで試す必要があります。
つぶした:
q_'$-_'^-:T;'^#\'^-'$#W{)2$5Y$5b+{:D[L"_T<W%_N#)_@>N+N#X-Ue>+-"_"W%-U"--2'<t2'>t'++'(')]=~0e>T,e<D3/1$T<N\+W%N#X?:X;}/2$-}g5b{" ^v<>"=}%]W=
展開およびコメント:
q "Read the input";
_'$- "Remove the end marker";
_'^-:T; "Remove the start marker and save the text";
'^# "With only the end marker removed, locate the start marker";
\'^-'$# "With only the start marker removed, locate the end marker";
W "Initialize the path number to -1";
{ "Do...";
) "Increment the path number";
2$ "Initialize the cursor position to that of the start marker";
5Y$5b+ "Convert the path number to base 5, then add a leading 5
(the leading 5 will act to initialize the column memory)";
{:D "For each digit in the path digit string:";
[ "Begin cases:";
L "0: Do nothing";
"_T<W%_N#)_@>N+N#X-Ue>+-"
"REFS: [ 1 ][ 2 ][ 3 ]45
1: [1] Calculate the distance to the end of the previous
line (0 if no such line)
[2] Calculate the length of the previous line (0 if
no such line)
[3] Calculate the distance to move backwards in the
previous line as the maximum of the length of the
previous line minus the column memory and 0
[4] Calculate the total distance to move as the sum
of [1] and [3]
[5] Subtract [4] from the cursor position";
_"W%-U"- "2: Start with a base of the logic of case 1, but with a
few operations adjusted.";
-2'<t2'>t " [1] Calculate the distance to the *start* of the
*next* line (0 if no such line)
[2] Calculate the length of the *next* line (0 if no
such line)
[3] Calculate the distance to move *forwards* in the
*next* line as the *minimum* of the length of the
*next line* and *the column memory*
[4] Calculate the total distance to move as the sum
of [1] and [3]";
'++ " [5] *Add* [4] *to* the cursor position";
'( "3: Decrement the cursor position";
') "4: Increment the cursor position";
]=~ "Execute the case corresponding to the path digit mod 5";
0e>T,e< "Clamp the cursor position to [0, text length]";
D3/ "Check if the path digit is not 0, 1, or 2...";
1$T<N\+W%N# "Calculate the current column";
X?:X; "If the above check succeeded, update the column memory";
}/ "End for each";
2$- "Subtract the end marker position from the cursor position";
}g "... While the above subtraction is nonzero";
5b "Convert the path number to base 5";
{" ^v<>"=}% "Map each digit in the path string to its operation symbol";
]W= "Clean up";
全体として、これは非常に簡単なソリューションです。これは、パスが機能するまで、0から始まる反復ごとに増分されるパス番号のベース5表現の数字を「実行」します。数字1- 4操作の上下左右にマップし、0何もしません。のパスを使用した最初の反復で0は、縮退したケースをキャッチします。aを含む他のすべてのパスは、0no-opが追加されたテスト済みパスの単なるバージョンであるため、選択されることはありません。
状態は、可能な限り最小限の方法でモデル化されます。開始マーカーと終了マーカーが削除されたテキスト、テキスト内のカーソル位置、および「列メモリ」。改行は主に他の文字と同様に扱われるため、行の概念はなく、カーソル位置は単なるインデックスです。これにより、左と右のデッドを簡単に移動できます。これは、デクリメントとインクリメントとして実装されます(テキストのサイズに固定されます)。上下に移動するのは少し複雑ですが、それでも管理は可能です。
コードの再利用は非常に重要な最適化戦術でした。この例は次のとおりです。
- 実行時に下に移動するためのコードを生成する方が、独自のコードを作成するよりも小さくなるように、上に移動するためのコードを記述します。これは、コードをコピーして上に移動し、いくつかの文字を削除/置換することによって行われます。
- 「列メモリ」の更新は、操作のロジックにコーディングされるのではなく、3で割ったパスの数字に基づいて条件付きで行われます。これ
5により、パス文字列の先頭にダミー操作を追加して列メモリを初期化することもできます。これは、0循環配列のインデックス付けと定義された操作が5つしかないため、no-opロジックを使用することにもなります。
全体として、私はこれがどのように出てきたかにとても満足しています。これは間違いなく、私がこれまでにコードゴルフの答えに入れた最も多くの仕事です(ツイートに収まる何かのために!?)。ただし、実行時間はかなりひどいです。CJamはそもそも最速の言語ではなく、このアルゴリズムはO(m * 5 n)のような複雑さを持っています。ここで、mは入力のサイズ、nは出力のサイズです。良いことの速度は重要ではありません!