ais523를위한 BackFlip을하십시오!


16

이 문제는 대한 상이다 ais523 에 대한 수상 은 " 올해의 신인 '카테고리를" PPCG 2016 최고의 ". 축하합니다!


BackFlipais523 사용자가 만든 난해한 프로그래밍 언어로 , 30 가지가 넘는 흥미로운 esolang을 만들었습니다 .

BackFlip은 Befunge 또는 > <> 와 같은 2D 언어 로, 명령 포인터가 텍스트 그리드 (프로그램)를 가로 지르고 위, 아래, 왼쪽 및 오른쪽으로 움직이며 문자에 따라 방향을 변경합니다. 비판적으로, BackFlip 프로그램의 그리드는 Langton 's Ant 와 같은 트래버스가 진행되면서 변경됩니다 .

이 문제를 해결하기 위해 BackFlip 프로그램은 항상 1x1 크기의 문자 만 포함하는 직사각형 텍스트 격자 (모든 줄의 길이는 동일)라고 가정 할 수 있습니다 ./\<>^V. ( .공간보다는 가시성에 사용됩니다.) 의미 상 여기서 사용할 BackFlip은 원래 spec 과 동일합니다 .

BackFlip의 명령어 포인터 (IP)는 항상 프로그램의 왼쪽 위 모서리에서 오른쪽으로 시작합니다. 발생할 수있는 명령에는 세 가지 유형이 있습니다.

  1. .no-op입니다. IP는 진행 방향으로 계속 진행됩니다. no-op는 no-op로 유지됩니다.

  2. /그리고 \거울입니다. 각도로 표시된 방향으로 IP를 반영한 ​​다음 다른 유형의 미러로 변경합니다 .

    • 예를 들어 IP 헤드가 왼쪽으로 왼쪽이면 왼쪽 \대신 위쪽으로 이동하기 시작하고가 \됩니다 /.
  3. <, >, ^V화살표이다. IP를 자신이 가리키는 방향으로 재 지정한 다음 IP가 향한 방향을 가리키는 화살표로 변경합니다 (IP가 이동 한 방향과 반대) .

    • 예를 들어 IP가 아래쪽으로 향하면 아래쪽이 >아닌 오른쪽으로 이동하기 시작 하고 IP의 방향 >이되므로 a ^가됩니다.

BackFlip 프로그램은 IP가 경계를 벗어날 때, 즉 그리드를 벗어나면 종료됩니다. 그것은 밝혀 모두 무한 루프가 불가능하기 때문에 결국 끝 공중제비 프로그램. (이것이 사실이라고 가정 할 수 있습니다.)

이 과제의 목표는 BackFlip 프로그램을 사용하고 프로그램이 종료되기 전에 명령어 포인터가 이동하는 횟수를 출력하는 프로그램이나 함수를 작성하는 것입니다. 즉, 프로그램 실행 과정에서 IP는 몇 단계를 거치나요? 여기에는 그리드의 초기 단계와 그리드의 마지막 단계가 포함됩니다.

예를 들어 명령어 포인터는 간단한 그리드에서 5 단계를 수행합니다 .....

 ....  <- empty 4×1 grid
012345 <- step number of the IP

따라서 출력은 ....입니다 5.

더 복잡한 4 × 2 그리드에서

\...
\.><

IP는 9 단계에서 그리드를 종료하므로 출력은 9다음과 같습니다.

step  grid  IP position (@)
0     \...  @....
      \.><   ....

1     \...   @...
      \.><   ....

2     /...   ....
      \.><   @...

3     /...   ....
      /.><   .@..

4     /...   ....
      /.><   ..@.

5     /...   ....
      /.<<   ...@

6     /...   ....
      /.<<   ..@.

7     /...   ....
      /.><   .@..

8     /...   ....
      /.><   @...

9     /...   ....
      \.><   ....
             @

바이트 단위의 가장 짧은 코드가 이깁니다.

원하는 경우 여러 줄 문자열 대신 행 배열 또는 문자 행렬로 입력을받을 수 있지만 ./\<>^V정수 opcode가 아닌 문자를 사용해야합니다 . 원하는 .경우 대신 공간을 사용할 수 있습니다 . 같은 문자 \를 입력에서 이스케이프 처리 해야하는 경우 괜찮습니다 . 출력은 항상 둘 이상의 정수입니다.

테스트 사례

....
5

\...
\.><
9

.
2

..
3

.
.
2

\
2

^
2

.^.
3

<.
2

\\
\/
7

>V
^<
6

>\
>/
6

\><
2

\><
\><
7

\><
\><
\><
12

\.V.
\.\<
5

\.V.
\./<
9

V./\
V./\
>./<
..\/
14

\V..
.^..
\/><
.V..
.^..
20

\.V.V.
\./.\<
.>\<..
..^.^.
31

\.V.V.V.
\./>/.\<
.>\>\<..
..^.^.^.
69

\.V.V.V.V.
\./>/>/.\<
.>\>\>\<..
..^.^.^.^.
145

\.V.V.V.V.V.V.V.V.V.V.
\./>/>/>/>/>/>/>/>/.\<
.>\>\>\>\>\>\>\>\>\<..
..^.^.^.^.^.^.^.^.^.^.
9721

1
BackFlip 솔루션을 만들 수 없다는 것은 부끄러운 일입니다 ...
HyperNeutrino

거울에 대해 혼란스러워 ... 방향을 왼쪽 => 위 및 위쪽 => 왼쪽으로 뒤집습니까?
officialaimm

1
@officialaimm 왼쪽에서 향하면 /IP가 올라가고, 위쪽으로 향하면 /IP가 벽에서 튀어 오르는 것처럼 보입니다 . (그러나 /IP가 그것을 터치 한 후에 백 슬래시에 대한 변화를 기억하십시오 .)
Calvin 's Hobbies

왜 '\\'<LF> '\ /'가 6 대신 7입니까?
tsh

답변:


3

자바 스크립트 (ES6), 158 바이트

f=(a,x=0,y=0,d=3)=>a[x]&&(c=a[x][y])?(a[x][y]=c=='.'?c:c=='/'?(d^=3,'\\'):c=='\\'?(d^=1,'/'):'v>^<'[d][d='^<v>'.search(c),0],f(a,d<3?x+d-1:x,d?y+d-2:y,d)+1):1

@tsh의 답변과 독립적으로 개발되었지만 놀랍도록 비슷합니다.

방향 ^<v>을 정수 0-3 으로 매핑 하는 것은 정규 표현식 메타 문자 .search('^')이므로 0 을 반환 한다는 사실에 의해 결정됩니다 ^.


나는 너무 소리 쳤다. 내가 기대했던 것과 비교하여 x와 y가 뒤집혔다는 것을 깨달을 때까지 나는 거기에서 매우 혼란 스러웠다.
Ørjan Johansen

@ ØrjanJohansen 좋은 지적입니다. 어쩌면 이해하기 쉽도록 어디서나 x를 y와 바꿔야합니다.
Neil

2

하스켈 , 333325 바이트

편집하다:

  • -8 바이트 : fpointfree로 만들고에 병합했습니다 b.

b의 목록을 String가져와을 반환합니다 Integer.

data C a=C{c::a->(a,C a)}
b g=[0,0]#([0,1],map(maybe(C$m 1)C.(`lookup`zip"./^>V<"[n,m(-1),a[-1,0],a[0,1],a[1,0],a[0,-1]]))<$>g)
[y,x]#(d,g)|g&y||g!!0&x=1|n@([f,e],_)<-(($d).c)?x?y$g=1+[y+f,x+e]#n
l&i=i<0||i>=length l
(f?i)l|(p,a:r)<-splitAt i l=(p++).(:r)<$>f a
n d=(d,C n)
a v d=(v,C$a$(0-)<$>d)
m s[d,e]=([s*e,s*d],C$m(-s))

온라인으로 사용해보십시오!

작동 원리

  • C aHaskell은 명시 적으로 선언하지 않고 유형을 재귀 적으로 허용하지 않기 때문에 사용되는 데이터 유형입니다. C또한 래핑 생성자이며 c해당하는 래핑 해제 기능입니다. 와 함께 만 사용됩니다 a=[Int].
    • 이 유형 C [Int]은 방향 ( [Int]) 인수를 사용하여 새 방향 쌍과 새 C [Int]값을 반환하는 함수로 셀 명령을 나타냅니다 .
  • b주요 기능입니다. 각 문자를 C값 으로 변환 한 다음을 호출합니다 #.
    • g 문자열 목록으로 그리드입니다.
    • 이후 \필요가 탈출 그래서 언급 가장 긴 문자 수, 그 결과는 대신 목록 조회를위한 기본 값으로 사용됩니다.
  • #을 사용하여 경계를 확인하고을 사용 &하여 새 그리드를 생성 하는 기본 시뮬레이션을 실행합니다 ?. [y,x]현재 위치, d현재 방향 및 g현재 그리드입니다. [f,e]다음 방향이며 그 방향 n과 다음 그리드의 쌍입니다.
  • l&i색인 i이 목록의 범위를 벗어 났는지 확인 합니다 l. ( True에서 더미 보호 조건을 피하기 때문에 범위를 벗어난 상태로 돌아갑니다 #.)
  • 되면 f(l!!i)==(d,x), (f?i)l==(d,m)여기서 m목록이다 li대체 th 요소 x.
    • 기술적 (?i)으로는 더 일반적인 렌즈이며,이 경우 (,) [Int]functor 인스턴스 와 함께 사용되는 목록의 i 번째 요소에 중점을 둡니다 .
  • n 점을 나타내는 함수입니다.
  • a v방향으로 화살표를 나타내는 함수 v입니다.
  • m s미러를 나타내는 함수입니다. s==1\\s==-1/.

1

자바 스크립트, 172 바이트

f=(a,d=3,x=0,y=0,n=1)=>(p=a[y]||[],q=p[x])?(p[x]=~(t='^<V>'.indexOf(q))?'^<V>'[d^2]:q=='/'?(t=3-d,'\\'):q=='\\'?(t=d^1,'/'):(t=d,q),f(a,t,x+(t&1&&t-2),y+(~t&1&&t-1),n+1)):n

그러나 내 컴퓨터에서 스택 오버플로가 발생하여 마지막 테스트 케이스를 테스트 할 수 없습니다. (램이 큰 머신이 있으면 작동해야합니다)

방향에 숫자를 사용합니다.

  • 0 : ^
  • 1 : <
  • 2 : V
  • 3 :>

d방향 번호를 보자 ...

  • '/'를 만나면 d = 3-d가 필요합니다.
  • '\'를 만나면 d = d ^ 1이 필요합니다.
  • '^ <V>'를 만나면 d = '^ <V>'가 필요합니다.

하자 (x, y)현재 위치 일, 다음 위치는 다음과 같습니다 x+(t&1&&t-2),y+(~t&1&&t-1)

노트 :

이 함수는 다음 형식으로 하나의 매개 변수를 사용합니다.

[ [ '\\', '.', 'V', '.', 'V', '.', 'V', '.', 'V', '.' ],
  [ '\\', '.', '/', '>', '/', '>', '/', '.', '\\', '<' ],
  [ '.', '>', '\\', '>', '\\', '>', '\\', '<', '.', '.' ],
  [ '.', '.', '^', '.', '^', '.', '^', '.', '^', '.' ] ]

여기에서 테스트

f=(a,d=3,x=0,y=0,n=1)=>(p=a[y]||[],q=p[x])?(p[x]=~(t='^<V>'.indexOf(q))?'^<V>'[d^2]:q=='/'?(t=3-d,'\\'):q=='\\'?(t=d^1,'/'):(t=d,q),f(a,t,x+(t&1&&t-2),y+(~t&1&&t-1),n+1)):n

    ;k=x=>x.split('\n').map(t=>t.split(''));
<textarea id=v>\.V.V.V.V.
\./>/>/.\<
.>\>\>\<..
..^.^.^.^.</textarea><br/><button onclick="r.textContent=f(k(v.value))">Solve</button>
<p>Result: <output id=r></output></p>


문서화하기 위해 Uncaught RangeError: Maximum call stack size exceeded16GB RAM을 사용하고 있습니다.
Zeb McCorkle

1
@ZebMcCorkle aha, "엄격한 사용"과 일부 var선언으로 인해 마지막 테스트 케이스를 통과한다는 것을 알 수 있습니다 (js 인터프리터는 엄격한 모드에서 테일 콜 최적화를
수행함

1

C, 232 221 바이트

d,n,t,m[4]={1,-1};char*w="><^V/\\.",*P;main(o,v)char**v;{for(P=v[1],m[2]=-(m[3]=strchr(P,10)-P+1);P>=v[1]&&P<strchr(v[1],0)&&*P^10;++n)*P=w[((o=d,t=strchr(w,*P)-w)<4)?d=t,o^1:(t<6)?d^=t-2,9-t:6],P+=m[d];printf("%d",n+1);}

첫 번째 인수로 입력을 받아 결과를 인쇄합니다. 입력에 적어도 하나의 줄 바꿈이 포함되어야합니다. 따라서 행이 하나만 있으면 줄 바꿈으로 끝나야합니다.

사용법 예 :

./backflip '....
';

고장:

d,                                          // Direction
n,                                          // Step counter
t,
m[4]={1,-1};                                // Movement offsets
char*w="><^V/\\.",                          // Command lookup
*P;                                         // Cursor location
main(o,v)char**v;{
    for(P=v[1],                             // Begin at 0,0
        m[2]=-(m[3]=strchr(P,10)-P+1);      // Find width of grid
        P>=v[1]&&P<strchr(v[1],0)&&*P^10;   // While inside grid:
        ++n)                                //  Increment step
        *P=w[                               //  Update the current cell
            ((o=d,t=strchr(w,*P)-w)         //  (store current direction & command)
              <4)?d=t,o^1:                  //   If <>^V, write backflip & set dir
            (t<6)?d^=t-2,9-t:               //   If / or \, write flip & bounce
            6],                             //   If ., write unchanged & continue
        P+=m[d];                            //  Move
    printf("%d",n+1);                       // Print result
}

1

파이썬 3 , 286 바이트

[f ()는 다음과 같은 형식으로 입력을받습니다. {(0,0):'/',(0,1):'.'}그래서 라인 배열을 해당 형식으로 변환하기위한 함수 g ()도 작성했습니다.]

def f(r):
 x=y=0;d='>';s=1
 while 1:
  try:c=r[y,x];m='>^<V'.find(d)
  except:break
  if(c=="\\"):d='V<^>'[m];r[y,x]="/"
  elif(c=="/"):d='^>V<'[m];r[y,x]="\\"
  elif(c!="."):r[y,x]='<V>^'[m];d=c
  x+=1if(d=='>')else-1if(d=='<')else 0;y+=1if(d=='V')else-1if(d=='^')else 0;s+=1
 return s

온라인으로 사용해보십시오!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.