矢印キーでテキストをナビゲートする


11

バックグラウンド

ほとんどの(中途半端な)テキストエディタでは、矢印キーを使用してテキストをナビゲートできます。上下に移動すると行を移動できますが、左右に移動すると行をまたがります。さらに、行がカーソルのX位置より短い場合、カーソルは行の最後に表示されますが、上下に移動し続けると同じX位置に戻ります。おそらく、次の視覚的な説明が役立ちます。

モーションの例

テキストの簡単なサンプルは次のようになります。カーソルは、このテキストの2文字の間、または最後に挿入されます。

-----
---
------

let's put the cursor here:

X-----
---
------

move down (v):

-----
X---
------

move left (<):

-----X
---
------

v

-----
---X
------

v (notice how the X position of the cursor has been maintained)

-----
---
-----X-

^

-----
---X
------

>  (more line wrapping)

-----
---
X------

<

-----
---X
------

^ (the X-position from earlier is no longer maintained due to the left-right motion)

---X--
---
------

チャレンジ

ASCIIテストのいくつかの行を考えて、開始位置から終了位置までの最短パスを見つけます。開始位置はで表され^、終了位置はで表され$、それぞれ1つしかありません。これらはテキストの一部とは見なされず、その行の「長さ」に寄与しません。

入力は、空白でない複数行のテキストで構成されます。出力は^v<>、最短パスの1つを示す一連の文字になります。オプションで、それぞれの末尾に追加の改行を想定することもできますが、それはナビゲーション可能なテキストの一部として含まれていません。

プログラムまたは名前付き関数を作成できます。勝者は、バイト単位で測定された最短の提出物になります。

I / Oの例

^Squares
are
fun$ny

vv<v  (which is better than the naive vv>>>)

Squares
^are
funny$

<vv

Alp$habet^
Song

v<^

Mary had a little lamb,
His fleece was white as snow,
And$ everywhere that ^Mary went,
The lamb was sure to go.

^^>>>>v>>>

$^degenerate case

(no output)

「カーソルがこのテキストでは2つの文字の間、あるいは末尾に挿入されます」 - 進行最初の例では先頭にカーソルを置くために
— SEは悪であるため、aditsuはやめ

各行には2つの端があります。「終わり」に編集されました。
— PhiNotPi

Vimでは矢印を使用できます。AIXボックスに実際のviがあります(スタートアップファイルにmapステートメントを追加しました)。「中途半端な」...うん
— ジェリーエレミヤ

最初の例の出力もである可能性がありますv<vvか?または、その行の最後の文字の後に終了しますか?
— mbomb007

@ mbomb007行の最後の文字の後に終了します。
— PhiNotPi

回答:


7

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は出力のサイズです。良いことの速度は重要ではありません!


ニース:)間接的にあなたがこれに多くの時間を費やしてしまったことに対して少し罪悪感を覚えます:p
— SEはEVILであるため、aditsuは終了します

2

Python 2:446

Q=input().split('\n');
def g(c):l=[l for l in Q if c in l][0];return Q.index(l),l.index(c)
a,b=g('^');c,d=g('$');Q=map(len,Q);Q[a]-=1;Q[c]-=1
if a==c:d-=b<d;b-=d<b
t=-1
while Q:
 l=[];T=t=t+1;x,y,z=a,b,b
 while T:l+=[T%5]*(T%5>0);T/=5
 for T in l:A=":x+=T+T-3;y=min(Q[x],z)";B="x<len(Q)-1";exec"if "+["","x"+A,B+A,"y:y=z=y-1\nelif x:x-=1;y=z=Q[x]","y<Q[x]:y=z=y+1\nelif "+B+":x+=1;y=z=0"][T]
 if(x,y)==(c,d):print''.join(' ^v<>'[x]for x in l);Q=0

簡単なソリューション。幅優先の検索を実行しています。tすべての異なるパスを反復処理します。tbase に変換し5ますが、ゼロ以外のエントリのみを使用します。1上、2下、3左、4右です。

カーソルの現在位置を3つの変数xに保持yしzます。上下に移動して行が短すぎる場合x、行、y列位置、およびz「非表示」列位置です。多くのifsが、移動中の変数の変化を決定します。

前処理は非常に長く、最初の4行はこのタスクのみを実行します。

長いテストケースには本当に長い時間がかかります。アルゴリズムの複雑さはO(N * 5 ^ N)です。Nは最短解の長さです。

使用法:単一の文字列として行を入力します(行で区切られます\n)"Alp$habet^\nSong"


1

CJam-274

まだ答えがありませんか?わかりました、ここに1つあります:)

qN/_{0:V;{_'^={[UVV]:B;;}{'$={[UV]:E;}{V):V;}?}?}/U):U;}/"^$"f-:,:A;{:X0=[X0=(_A=X2=_@e<\]X?}:U;{:X0=A,(=X[X0=)_A=X2=_@e<\]?}:D;{:X1=[X~;(_]{X0=[X0=(_A=_]X?}?}:L;{:X1=X0=A=={X0=A,(=X[X0=)0_]?}[X~;)_]?}:R;[[BM]]{_{0=2<E=},_{0=1=o0}{;[{"U^DvL<R>"2/\f{[~@1/~@\+@@~\]}~}/]1}?}g;

http://cjam.aditsu.net/で試してみてください ... Maryの例またはそのサイズのものを除き、おそらくjavaインタープリターが必要です。


1
WTF?274 !!!!!!
— オプティマイザー

@Optimizerははは、まあ、私はそれで十分な時間を無駄にし、あなたが望むならもっと先に行き、それをもっとゴルフします:p
— SEはEVILであるため
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.