당신의 차는 단지 우회전합니다!


49

소개

장애물 코스에서 런 어웨이 차량에 갇혀 있다는 불행이 있습니다. 자동차의 모든 기능이 반응하지 않아 스티어링 시스템이 손상되었습니다. 똑바로 운전하거나 우회전 할 수 있습니다. 자동차를 안전으로 안내 할 수 있습니까?

역학

자동차는 8x8지도의 왼쪽 상단에서 시작하여 오른쪽 하단에서 안전을 얻으려고합니다. 자동차는 90도 단위로 측정 된 방향 (초기 오른쪽)을가집니다. 자동차는 다음 두 가지 조치 중 하나를 수행 할 수 있습니다.

  1. 한 칸 앞으로 이동하거나
  2. 시계 방향으로 90도 회전 한 다음 한 칸 앞으로 이동

자동차는 단일 사각형에서 180도 회전을 수행 할 수있을 정도로 급하게 회전 할 수 없습니다.

사각형 중 일부는 장애물입니다. 차가 장애물 광장에 들어가면 충돌합니다. 8x8 코스 외부의 모든 것은 장애물로 간주되므로 코스에서 내리는 것은 충돌과 같습니다.

오른쪽 아래 광장은 안전 광장으로 차가 장애물 코스를 벗어날 수 있도록합니다. 시작 광장과 안전 광장은 장애물이 아니라고 가정합니다.

태스크

장애물 코스를 나타내는 8x8 배열 (매트릭스, 목록 목록 등)을 입력으로 사용하는 프로그램이나 함수를 작성해야합니다. 이 프로그램은 부울 또는 비슷한 것을 반환하거나 인쇄합니다. 자동차가 충돌없이 안전한 정사각형으로 만들 수있는 경우 (예 :지도를 해결할 수있는 경우) 출력은 True이고 그렇지 않으면 False입니다.

채점

표준 코드 골프 규칙-승자가 가장 적은 바이트를 가진 코드입니다.

보너스 :

  • 해결 가능한지도의 경우, 코드가 자동차를 안전한 광장으로 안내하는 일련의 유효한 운전자 입력을 출력하는 경우 점수에서 10 % 포인트를 차감합니다. 출력 형식의 예는 SRSSR(직선, 오른쪽, 직선, 직선, 오른쪽을 나타냄) 일 수 있습니다. 이 출력은 표준 True출력을 대체합니다 .

  • 해석 할 수없는 맵의 경우, 코드 출력이 충돌을 피할 수없는 상황과 장애물 코스를 영원히 운전할 수있는 상황을 구별하는 경우 점수에서 10 % 포인트를 빼십시오. Crash충돌을 피할 수 없거나 Stuck자동차가 장애물 코스에 영원히 갇힌 경우 출력 예가 표시 될 수 있습니다 . 이러한 출력은 False해결할 수없는 맵 의 표준 출력을 대체합니다 .

프로그램에 다음과 같은 8x8 배열이 제공되는 경우 :

[[0, 0, 0, 0, 0, 1, 0, 0],
 [0, 0, 0, 0, 0, 0, 1, 0], 
 [1, 1, 0, 0, 0, 0, 0, 0], 
 [0, 1, 0, 1, 0, 0, 0, 0], 
 [0, 0, 1, 1, 0, 0, 0, 0], 
 [0, 0, 0, 0, 1, 0, 1, 0], 
 [0, 0, 0, 0, 0, 0, 1, 0], 
 [0, 1, 1, 0, 0, 0, 1, 0]]

다음과 같은지도로 해석되며 검은 색 사각형이 장애물을 나타냅니다.

여기에 이미지 설명을 입력하십시오

가능한 해결책은 다음과 같습니다.

여기에 이미지 설명을 입력하십시오

솔루션이 존재하므로 프로그램은 True이 맵에 대해 리턴 / 인쇄해야합니다 . 여기에 표시된 동작 순서는 SSSSRSRRRSRSSRRRSSRSSS입니다.


2
좀 썼다 매우 간단한 테스트 케이스를 Crash하고 Stuck. 그들은 그들이 얼마나 오래 있기 때문에 여기에 있습니다. 행 2가 채워졌고 다른 모든 항목은 비어 있습니다-> Crash. 7 번 열, 다른 모든 항목 비우기->Stuck
undergroundmonorail

3
백분율 과 달리 백분율 포인트 에 대해 혼란 스럽습니다 . 두 보너스 중 하나를 받으면 점수에 0.9가 곱해집니다. 둘 다 0.8 또는 0.9 ^ 2를 곱합니까?
undergroundmonorail

3
물론 S와 C는 괜찮습니다. 내 결과는 단지 제안 일뿐입니다.
phosgene

13
"두 가지 잘못이 옳은 것은 아니지만 세 가지 왼손은 옳다." -아빠
hoosierEE 2009 년

2
"차는 0에서 3 개의 왼쪽 만 만들 수 있습니다!"
feersum

답변:


17

자바 스크립트 (ES6) - 122 124 148 162 172 178 187 190 193 208 바이트

이 코드를 개선하는 방법에 대한 유용한 제안에 대해 Optimizer와 DocMax에게 감사드립니다.

F=a=>(D=(x,y,d)=>!D[i=[x,y,d]]&&(D[i]=1,x-=~d%2,y-=~-~d%2,x*y==49||!((x|y)&8||a[y][x])&&(D(x,y,d)||D(x,y,~-d%4))),D(-1,0))

true해결할 수있는 경우에는 false(truthy), 해결할 수없는 경우 에는 (falsy)를 반환 합니다.

JavaScript 1.7 기능으로 인해 현재 Firefox에서만 작동합니다.

테스트 보드


1
이것은 193 바이트 D=(x,y,d,t,a)=>!t[i=x+y*8+d*64]&&(t[i]=1,x+=d==0?1:d==2?-1:0,y+=d==1?1:d==3?-1:0,x==7&&y==7||!((x|y)&~7||a[y][x])&&G(x,y,d,t,a));G=(x,y,d,t,a)=>D(x,y,d,t,a)||D(x,y,d+1&3,t,a);F=a=>G(0,0,0,[],a)입니다.
Optimizer

1
172 : D=d=>!t[i=x+y*8+d/4]&&(t[i]=1,x+=d?d^2?0:-1:1,y+=d^1?d^3?0:-1:1,x==7&&y==7||!((x|y)&~7||b[y][x])&&G(x,y,d));G=(X,Y,d)=>D(d,x=X,y=Y)||D(d+1&3,x=X,y=Y);F=a=>G(0,0,0,b=a,t={})-테스트되었습니다.
Optimizer

1
@Optimizer 여전히 두 번째 테스트 사례에 적용 [[0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]]됩니다. 그것은 거짓을 주어야한다.
나와 내 고양이

2
이후 때문이다 x하고 y모두 전역이, 당신이 ... 페이지를 다시로드하기 전에 두을 testcases를 실행할 수 없습니다
최적화

1
당신은 대체하여 9 이상 총을 절약 할 수 x+=d?d^2?0:-1:1x+=d&1?0:1-dy+=d^1?d^3?0:-1:1함께 y+=d&1&&2-d.
DocMax

10

파이썬 2-123125133146148150154160

True성공, False실패.

def f(h=1,v=0,b=0,x=0,y=0,c=[]):s=x,y,h,v;a=b,x+h,y+v,c+[s];return(s in c)==(x|y)&8==b[y][x]<(x&y>6or f(h,v,*a)|f(-v,h,*a))

와 같은 입력을 제공해야합니다 f(b=var_containing_board).

람다 버전-154

0실패, True성공을 위해 (거짓)을 반환합니다 .

F=lambda b,x=0,y=0,h=1,v=0,c=[]:0if[x,y,h,v]in c or x|y>7or x|y<0 or b[y][x]else x&y==7or F(b,x+h,y+v,h,v,c+[[x,y,h,v]])or F(b,x+h,y+v,-v,h,c+[[x,y,h,v]])

함수를 람다보다 짧게 만든 Will과 Brandon에게 감사합니다. 가로 스크롤을 더 추가하기 위해 : D

뛰어난 비트 -bashing 및 로직을위한 xnor에 감사합니다!

편집 노트 : b[y][x]범위를 벗어날 때 절대 실행되지 않을 것이라고 확신합니다 . 우리가 보드 외부에 있기 때문에 기록 확인 s in c은입니다 False. 그러면 경계 점검 (x|y)&8이됩니다 8. 그러면 파이썬은 ==처음 두 값 이 이미 다르기 때문에 마지막 값조차 확인하지 않습니다 .


1
기능 버전은 두 개의 if를 모두 리턴 할 수 있습니다. 반환 혼자 falsy입니다 None을 돌려, 당신은 또한 호의를 반환 년 그냥 0을 반환 할 필요가 없습니다)

수표를 뒤집 으면 두 경우 모두를 결합 할 수 있습니다
Will

두 개의 반품 명세서를 결합 할 수 있습니까?
Brandon

1
@ 윌 고마워, 나는 그것을하는 더 좋은 방법이 있다는 것을 알고 있었다 : D 음, 나는 구문 오류를 일으키지 않는 제거 할 공간을 찾을 수 없었다. 나는 왜 실제로 x|y>7or효과 x|y<0or
있는지는

1
로 시작하는 8 진 리터럴을 만들 수 있습니다 0o.
feersum

9

C (GNU-C), 163 바이트 * 0.9 = 146.7

#C (GNU-C), 186 바이트 * 0.9 = 167.4

내 새 버전은 부호없는 정수가 아닌 부호있는 정수를 사용합니다. 이전에는 서명 된 오른쪽 이동이 두려웠지만 부호 비트가 목표 사각형이므로 그 이후에 어떤 일이 발생하는지는 중요하지 않습니다.

이 함수는 64 비트 정수 형식의 비트 배열 (하나는 차단 된 사각형을 나타냄)을 취합니다. 비트는 책을 읽는 것과 같은 방식으로 가장 중요하게 정렬됩니다. 충돌의 경우 -1, 영구적으로 운전하는 경우 0, 오른쪽 하단 모서리로 탈출하는 경우 1을 반환합니다.

g(long long o) {
    typeof(o) a=0,i=255,r=1,u=0,l=0,d=0,M=~0LLU/i,D;
    for( ;i--;d = D<<8&~o)
        a |= D = d|r,
        r = (r|u)*2&~M&~o,
        u = (u|l)>>8&~o,
        l = ((l|d)&~M)/2&~o;
    return a<0?:-!(d|r|u|l);
}

테스트 프로그램

f(long long o){typeof(o)a=0,i=255,r=1,u=0,l=0,d=0,M=~0LLU/i,D;for(;i--;d=D<<8&~o)a|=D=d|r,r=(r|u)*2&~M&~o,u=(u|l)>>8&~o,l=((l|d)&~M)/2&~o;return a<0?:-!(d|r|u|l);}
{
    char* s[] = {"Crash", "Stuck", "Escape"};
    #define P(x) puts(s[f(x)+1])
    L ex = 0x4640500C0A034020;
    P(ex);
    L blocked = 0x4040404040404040;
    P(blocked);

    L dead = 0x10002;
    P(dead);

    return 0;
}

산출

Escape
Stuck
Crash

파이썬 배열-육각 변환기 :

a2b=lambda(A):"0x%X"%sum(A[i/8][i%8]<<i for i in range(64))

1
교체 memset(&M,~1,8)로 (15 개 문자) M=~(-1ULL/255)(14 문자)를.
R ..

@R .. 좋은 하나! 그로부터 -4 바이트.
feersum

2
나는 입력 형식을 좋아한다 – 매우 시원하다!
phosgene

P(0x00fefefefefefefe);= ( 'crash')가 발생합니다. = (오른쪽 상단으로 직진, 1 턴, 직각으로 똑바로되어야합니다. P(0x00eeeeeeeeeeeeee);(4 번째 열의 막 다른 골목) 와 동일 . a처음 에 할당 할 필요는 없다고 생각합니다 .

@tolos 행 / 열-주문 순서를 바꿨습니다. 맨 위 행과 오른쪽 열을 열려면이어야합니다 0x7f7f7f7f7f7f7f00. 또한 a나중에 추가 비트의 ORing으로 만 수정되므로 초기화해야 하므로 초기에 원치 않는 비트를 설정할 수 없습니다.
feersum

6

파이썬, 187 (213)

207 자, 인쇄 경로 10 % 보너스

b=map(ord," "*9+" ".join("".join("o "[i]for i in j)for j in input())+" "*9)
def r(p,d,s):
 p+=(1,9,-1,-9)[d]
 if b[p]&1<<d:b[p]^=1<<d;return(s+"S")*(p==79)or r(p,d,s+"S")or r(p,(d+1)%4,s+"R")
print r(8,0,"")

테스트 입력에서 약간 다른 경로를 찾습니다. SSSSRSRSRRSSRSSRRSRSSRSSSSS

일반적인 접근법은 먼저 입력을 공백과 os 로 바꾸는 것 입니다. 공백은의 16 진수 20이므로 4 개의 하위 비트 모두 설정이 해제됩니다. o의 16 진수가 6F있으므로 하위 4 비트가 모두 설정됩니다.

os 테두리가 보드 주위에 배치되어 잘못된 인덱스에 대해 걱정할 필요가 없습니다.

보드 위를 걸을 때 우리는 각 타일의 비트를 사용하여 측면에서 올 때 통과 할 수 있는지 확인합니다. 이런 식으로 무한 루프를 피합니다. 출구 방향은 입구 방향에 따라 다르므로 타일을 두 번 방문 할 수 있으므로 타일 당 단일 부울만으로는 충분하지 않습니다.

그런 다음 안전한 경로를 재귀 적으로 검색합니다.


3
"자동차는 8x8지도의 왼쪽 상단에서 시작합니다" 등 9대신 하드 코드 할 수 w=len(b[0])+1없습니까?
FryAmTheEggman

@FryAmTheEggman 감사합니다. 어떻게 간과 할 수 있었습니까? : D

당신은 당신의 삼항 문을 반대하고 교체 할 수 있습니다 p==79p-79. 전에 공백 없이이 두 가지 방법으로 구문 오류가 발생했습니다 else. 그 트릭은에서만 작동한다고 생각합니다 if.
FryAmTheEggman

@FryAmTheEggman 깊이 테스트는 재귀 전에해야한다고 생각합니까? 대신 부울에 의한 곱셈을 가지고 놀고 있습니다.
것입니다

7
방금 정말 깔끔한 트릭을 발견했습니다. 아마 -~x== x+1이지만 두 단항 연산자는 곱셈, 나눗셈 및 계수보다 우선 순위가 높습니다! 그렇게 (d+1)%4될 수 있습니다 -~d%4! 이것은 또한 작동 x-1하지만 ~-x대신 사용하십시오.
FryAmTheEggman

6

자바 스크립트-270-20 % = 216262-20 % = 210 바이트

두 보너스를 모두 얻는 (그리고 말도 안되는 스택 깊이를 초래하지 않는) 적어도 하나의 솔루션이 있어야하기 때문에 ...

축소 :

V=I=>{n=[N=[0,0,0]];v={};v[N]='';O='C';for(S='';n[0];){m=[];n.map(h=>{[x,y,d]=h;D=i=>[1,0,-1,0][d+i&3];p=v[h];for(j=2;j--;){O=v[c=[X=x+D(j),Y=y+D(3-3*j)),d+j&3]]?'K':O;J=X|Y;J<0||J>7||I[Y][X]||v[c]?O:(m.push(c),v[c]=p+'SR'[j])}S=(x&y)>6?p:S});n=m;}return S||O;};

넓히는:

V = I => {
    n = [N=[0,0,0]];
    v = {};
    v[N] = '';
    O = 'C';

    for( S = ''; n[0]; ) {
        m = [];
        n.map( h => {
            [x,y,d] = h;
            D = i => [1,0,-1,0][d+i&3];
            p = v[h];
            for( j = 2; j--; ) {
                O = v[c = [X = x+D(j),Y = y+D(3-3*j),d+j&3]] ? 'K' : O;
                J = X|Y;
                J<0 || J>7 || I[Y][X] || v[c] ? O : (
                    m.push( c ),
                    v[c] = p + 'SR'[j]
                );
            }

            S = (x&y) > 6 ? p : S;
        } );
        n = m;
    }
    return S || O;
};

v(x,y,d)(x, y) 좌표 및 진입 방향에 해당하는 상태 3 배인 키가있는 해시 테이블입니다 d. 각 키에는 키로 표시되는 상태에 도달하는 데 필요한 S(직선) 및 R(오른쪽 회전 ) 문자열 인 관련 값이 있습니다.

또한이 코드는 n아직 처리되지 않은 트리플의 스택 (변수 )을 유지합니다 . 스택에는 처음에 (0,0) 셀에서 자동차가 오른쪽을 향한 상태에 해당하는 트리플 (0,0,0) 만 포함됩니다. 외부 루프 for( S = ... )에서 루틴은 처리되지 않은 트리플이 남아 있는지 확인합니다. 그렇다면 내부 루프를 통해 처리되지 않은 트리플을 각각 실행합니다 n.map( ....

내부 루프는 다섯 가지를 수행합니다.

  1. 현재 상태에서 두 가지 가능한 이동 (직선으로 운전, 우회전) 계산
  2. 이러한 이동 중 하나가 해시 테이블에 이미 등록 된 상태로 이어지는 경우 추가 처리를 위해 무시됩니다. K그러나 FALSE 출력을 (고정) 으로 플래그 지정합니다 . 그러나 충돌없이 자동차가 계속 원형을 유지할 수있는 하나 이상의 루프를 찾았 기 때문에.
  3. 상태가 합법적이고 참신한 경우 외부 루프의 다음 패스에 대해 해시 테이블 ( v) 및 처리되지 않은 트리플의 스택에 추가됩니다.m
  4. 새 상태가에 등록 v되면 해당 값은 원래 상태 값 (이동 순서)에 플러스 R또는 S현재 이동을 기준으로 설정됩니다.
  5. 경우 xy되어 7, 원래 상태 (원래의 상태에 도달하는 데 걸리는 동작의 시퀀스)의 값에 복사되고 S이 이동 시퀀스는 상기 문제에 대한 해결책이 때문에

내부 루프가 종료되면 n(스택)이 m(새 스택)으로 대체됩니다 .

외부 루프가 종료 된 후 (새로운 상태에 도달하지 않은 경우) 함수는 출력을 반환합니다. (7,7) 셀에 도달 S하면이 셀로 이어지는 일련의 이동이 포함되어 출력됩니다. 셀에 도달하지 않은 경우, S빈 문자열 및 출력에 이르기까지 일상 폭포 될 것입니다 O포함, K루프가 발견, 또는 경우에만 경우 (부착) C(충돌) 자동차가 필연적으로 충돌 할 경우.


1
OP에서 확인을 받으면 'Crash'와 'Stuck'의 이름을 'C'와 'S'로 바꿀 수 있습니다.
FryAmTheEggman

아 그러면 조금 절약됩니다. 감사. ;)
COTO

코드가 무엇을하고 있는지 설명 할 수 있습니까? 나는 머리 나 꼬리를 만들 수 없습니다.
phosgene

@phosgene : 자세한 설명을 인라인으로 포함 시켰습니다.
COTO

그것은 영리한 절차입니다. 아무것도 낭비되지 않습니다.
phosgene 2016 년

4

파이썬 339-10 % = 305 바이트

재귀 깊이 우선 검색을 사용했는데을 통해 성공하면 조기에 종료됩니다 exit. 또한의 형태로 성공 경로를 인쇄 00001010101010101010101110100111001000, 0직선에 대한 1권리를. 답변은 깊이 우선이므로 최적보다 길 것입니다. 알고리즘에 대한 일부 최적화로 인해 바이트 수가 상당히 줄어 듭니다.

b=input()
D=[(-1,0),(0,-1),(1,0),(0,1)]
def a(l):
 x,y=0,0
 v=2
 for d in l:
  if d=='1':v=(v+1) % 4
  x+=D[v][0]
  y+=D[v][1]
  if x<0 or x>7 or y<0 or y>7:return 0,x,y
  if b[y][x]:return -1,x,y
 return 1,x,y
def c(l):
 if len(l) < 39:
  t,x,y=a(l)
  if t==1:
   if (x,y)==(7,7):
    print l;exit(0)
   c(l+"0")
   c(l+"1")
c("")
print 0

3
이것은 Python 2이므로 afor루프 와 같이 들여 쓰기를 위해 탭과 공백을 혼합 할 수 있습니다 . 또한 연산자 주위에 공백이 필요하지 않습니다 (예 : (v+1) % 4->) (v+1)%4. 예를 들어, 줄에 또는 등 ;이없는 경우 를 사용하여 여러 줄을 한 줄로 결합 할 수도 있습니다 . 일부 다른 골프를 친다 : , , . 행운을 빌어 :)ifforc(l+"0");c(l+"1")x,y,v=0,0,2x|y>7 or x|y<0x==y==7
FryAmTheEggman
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.