화살표 키를 사용하여 텍스트 탐색


11

배경

대부분의 (반쯤 괜찮은) 텍스트 편집기에서는 화살표 키를 사용하여 텍스트를 탐색 할 수 있습니다. 위와 아래를 사용하면 선을 탐색 할 수 있으며 왼쪽과 오른쪽은 선을 가로 질러 이동할 수 있지만 줄 바꿈됩니다. 또한 선이 커서의 X 위치보다 짧은 경우 커서는 선 끝에 표시되지만 계속 위나 아래로 이동하면 동일한 X 위치로 돌아갑니다. 아마도 다음과 같은 시각적 설명이 도움이 될 것입니다.

운동의 예

간단한 텍스트 샘플은 다음과 같습니다. 이 텍스트에서 커서는 두 문자 사이에 또는 끝에 삽입됩니다.

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

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 테스트가 제공되면 시작 위치에서 끝 위치까지 가장 짧은 경로를 찾으십시오. 시작 위치는로 표시되고 ^끝 위치는로 표시되며 $각각 하나만 표시됩니다 . 이들은 텍스트의 일부로 간주되지 않으며 해당 행의 "길이"에 영향을 미치지 않습니다.

입력은 공백이 아닌 여러 줄의 텍스트로 구성됩니다. 출력은 ^v<>가장 짧은 경로 중 하나를 표시 하는 일련의 문자입니다. 선택적으로 각각의 끝에 추가 줄 바꿈을 가정 할 수 있지만 탐색 가능한 텍스트의 일부로 포함되지는 않습니다.

프로그램이나 명명 된 함수를 작성할 수 있습니다. 우승자는 가장 짧은 제출물이며 바이트 단위로 측정됩니다.

예제 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)

"커서가이 텍스트에서 두 문자 사이에 또는 끝에 삽입됩니다"- 첫 번째 예에서 커서를 시작 부분에
놓으십시오.

모든 줄에는 두 개의 끝이 있습니다. "끝"으로 편집되었습니다.
PhiNotPi

Vim은 화살표를 허용합니다. AIX 상자에 실제 vi가 없습니다 (시작 명령문에 맵 문을 추가했습니다). "halfway decent"... yep
Jerry Jeremiah

첫 번째 예제의 출력도 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은 퇴화 사례를 포착합니다. 를 포함하는 다른 모든 경로 0는 선택되지 않은 이미 테스트 된 경로의 버전이므로 선택되지 않습니다.

상태는 가능한 최소한의 방식으로 모델링됩니다 : 시작 및 끝 마커가 제거 된 텍스트, 텍스트의 커서 위치 및 "열 메모리". 줄 바꿈은 대부분 다른 문자와 같이 취급되므로 행 개념이 없으며 커서 위치는 색인 일뿐입니다. 이로 인해 왼쪽과 오른쪽 데드가 간단하게 움직일 수 있으며, 텍스트 크기에 맞게 클램핑하여 증가 및 증가로 구현됩니다. 위아래로 이동하는 것은 조금 까다 롭지 만 여전히 관리 가능합니다.

코드 재사용은 매우 중요한 최적화 전략이었습니다. 이에 대한 예는 다음과 같습니다.

  • 자체 코드를 작성하는 것보다 런타임에 아래로 이동하는 코드를 생성하는 것이 더 작은 방식으로 위로 이동하기위한 코드 작성 이것은 몇 문자 위로 이동하고 제거 / 바꾸기위한 코드를 복사하여 수행됩니다.
  • "열 메모리"업데이트는 경로 논리를 연산 논리로 코딩하는 대신 3으로 나눈 경로를 기준으로 조건부로 수행됩니다. 또한 5경로 문자열의 시작 부분에 더미 연산을 추가하여 열 메모리를 초기화 할 수 있습니다. 0순환 배열 인덱싱으로 인해 no-op 논리도 사용 되며 5 개의 정의 된 연산 만 있습니다.

전반적으로, 나는 이것이 어떻게 나왔는지 매우 기쁘게 생각합니다. 이것은 분명히 코드 골프 답변에 들어간 가장 많은 작업입니다 (트위트에 맞는 것!?). 그러나 실행 시간은 꽤 무섭습니다. CJam은 시작하기에 가장 빠른 언어는 아니며이 알고리즘은 O (m * 5 n ) 와 같이 복잡합니다 . 여기서 m 은 입력 크기이고 n 은 출력 크기입니다. 좋은 속도는 중요하지 않습니다!


니스 : 나는 간접적으로이에 너무 많은 시간을 할애 만들기위한 약간의 죄책감을 느낄 : P
aditsu 종료 SE 악이기 때문에

2

파이썬 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하지만 0이 아닌 항목 만 사용하십시오. 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

아직 대답이 없습니까? 좋아, 여기에 하나가 있습니다 :)

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;

Mary 예제 또는 해당 크기의 것을 제외하고 http://cjam.aditsu.net/ 에서 시도 하십시오 .Java 인터프리터가 필요할 것입니다 .


1
WTF? 274 !!!!!!
최적화

@Optimizer hahaha, 글쎄, 나는 그것에 충분한 시간을 낭비했다.
SE 악이기 때문에 aditsu 종료
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.