소행성 장을 성공적으로 탐색


36

소개

소행성을 성공적으로 탐색 할 수있는 가능성은 약 3,720에서 1이라는 것을 누구나 알고 있습니다.

당신의 인공적인 삶을 두려워해서, 당신은 우주선의 독특한 방언 ( 선호하는 코드 골프 언어를 읽으십시오 )에서 소행성 회피 ASCII 미로를 가져갈 길을 결정하는 소행성 회피 프로그램 을 코딩하기로 결정합니다 .

입력

Millenium Falcon에는 다음과 유사한 데이터를 제공하는 소행성 필드 매핑 프로그램이 있습니다.

|   #####           #########  |
| ######  #          ###   #   |
|   # #  #  #  ####   #        |
@              ##    ####       
|#   #   #       ###   ##      |
|##      ##      ####   #  #   |
|####           ##### #   ##   |

상단 행은 팔콘 왼쪽, 하단 행은 팔콘 오른쪽, 열은 선박 앞에있는 것을 나타냅니다.

  • 각각 #은 장애물입니다.
  • 각 공간은 배가 날 수있는 빈 공간입니다.
  • 입력은 항상 7 자입니다. 소행성 매핑 너비 제한입니다.
  • 입력 길이는 항상 32 자입니다 (필드 자체는 30 자, 시작 및 끝 한계는 2 자). 이것이 소행성 매핑 깊이 한계입니다. 세로 막대 |는 매핑의 시작과 끝을 표시합니다.
  • @팔콘입니다. 항상 입력의 가운데 행 (4 번째 행)과 첫 번째 열에 있습니다.
  • 마지막 열의 세로 막대에 남은 공간은 선박이 도착해야하는 곳입니다. 항상 입력의 가운데 행 (4 번째 행)과 마지막 열에 있습니다.

입력은 여러 줄 문자열, 문자열 배열, STDIN 또는 함수 매개 변수에서 가져 오거나 파일에서 읽을 수 있습니다.

가능한 기동

당신은 TIE-Fighters에 의해 추구되므로 항상 앞으로 나아가 야합니다. 따라서 선박이 각 단계에서 3 가지 방법으로 비행 할 수 있습니다.

  • - 앞으로

  • / 앞으로 좌회전

  • \ 앞으로 우회전

예를 들어, 다음은 유효한 경로입니다.

@---

  --
 /  \ /
@    -

   -
  / \
 /   \
@     \

보시다시피, 열당 항상 정확히 하나의 이동이 있습니다. 팔콘은 쓰레기의 한 조각이므로 격렬한 회전을 할 수 없습니다. 같은 어떤 수단 이동 /\이상이 \/되는 허용 . -두 개의 반대 턴 사이에 최소한 하나의 순방향 전진이 있어야합니다 . 한편, 상기 한 바와 같이, 여러 단계를 위해 한 방향으로 돌리는 것이 가능하다.

한 번의 이동으로 선박이 장애물이있는 지점에있게되면 팔콘이 추락합니다. 예를 들어 다음과 같은 동작으로 인해 충돌이 발생합니다.

@-#

@
 \
  #

  #
 /
@

이것은 충돌이 아닙니다.

@-#
  \
   -

산출

끝까지의 유효한 경로와 동일한 소행성 필드 ASCII를 출력해야합니다. 팔콘은 시작 지점 대신 끝 지점에 인쇄되어야합니다.

예를 들어, 이전에 제공된 입력 예제의 유효한 출력은 다음과 같습니다.

|   #####           #########  |
| ######  #--------  ###   #   |
|   # #  #/ #  ####\  #        |
 ---------      ##  \ #### ----@
|#   #   #       ### \ ## /    |
|##      ##      #### \ #/ #   |
|####           ##### #-- ##   |

당신의 경로는 팔콘을 추락하지 않아도됩니다. 가능한 최단 경로 일 필요는 없습니다.

끝까지 가능한 경로가 항상 하나 이상 있다고 가정 할 수 있습니다.

소행성 필드가이 포스트에서와 같이 정확하게 인쇄되는 한 파일 또는 이와 동등한 형식으로 STDOUT으로 출력 할 수 있습니다 (예 : 경로의 좌표리스트 출력이 유효하지 않음).

테스트 사례

  • 정상적인 소행성 분야

    |   #####           #########  |
    | ######  #          ###   #   |
    |   # #  #  #  ####   #        |
    @              ##    ####       
    |#   #   #       ###   ##      |
    |##      ##      ####   #  #   |
    |####           ##### #   ##   |
    

    가능한 출력

    |   #####           #########  |
    | ######  #--------  ###   #   |
    |   # #  #/ #  ####\  #        |
     ---------      ##  \ #### ----@
    |#   #   #       ### \ ## /    |
    |##      ##      #### \ #/ #   |
    |####           ##### #-- ##   |
    
  • 초 정기 소행성 분야

    |# # # # # # # # # # # # # # # |
    | # # # # # # # # # # # # # # #|
    |# # # # # # # # # # # # # # # |
    @ # # # # # # # # # # # # # #   
    |# # # # # # # # # # # # # # # |
    | # # # # # # # # # # # # # # #|
    |# # # # # # # # # # # # # # # |
    

    가능한 출력

    |# # # # # # # # # # # # # # # |
    | # # # # # # # # # # # # # # #|
    |# # # # # # # # # # # # # # # |
     -# #-# #-# #-# #-# #-# #-# #--@
    |#\#/#\#/#\#/#\#/#\#/#\#/#\#/# |
    | #-# #-# #-# #-# #-# #-# #-# #|
    |# # # # # # # # # # # # # # # |
    
  • 죽음의 별의 핵심

    |    #    #    #         #     |
    |         #    #    #          |
    |    #    #    #    #    #     |
    @    #    #    #    #    #      
    |    #    #         #    #     |
    |    #    #    #    #    #     |
    |    #         #    #    #     |
    

    가능한 출력

    |    #    #    #   --    #     |
    |  ---    #    #  / #\   -     |
    | /  #\   #    # /  # \ /#\    |
     -   # \  #    #/   #  - # ----@
    |    #  \ # ----    #    #     |
    |    #   \#/   #    #    #     |
    |    #    -    #    #    #     |
    
  • 데스 스타 트렌치

    |##############################|
    |##############################|
    |##############################|
    @                               
    |##############################|
    |##############################|
    |##############################|
    

    산출

    |##############################|
    |##############################|
    |##############################|
     ------------------------------@
    |##############################|
    |##############################|
    |##############################|
    
  • 소행성 동굴

    |### ##########################|
    |## # ############### ## ######|
    |# ###  ######## ### ## # #####|
    @ ###### ###### ### ## ###      
    |########  ### ### ## #########|
    |########## # ### ## ##########|
    |###########              #####|
    

    가능한 출력

    |###-##########################|
    |##/#\############### ##-######|
    |#/###--######## ### ##/#\#####|
     -######\###### ### ##/###-----@
    |########--### ### ##/#########|
    |##########\# ### ##/##########|
    |###########--------      #####|
    

채점

R2D2는 늪지에서 수영을하기 때문에 바쁘기 때문에 팔콘 컨트롤러를 직접 프로그래밍해야합니다. 따라서 가장 짧은 코드가 승리 합니다.


@DJMcMayhem : 기술적으로 첫 번째 줄은 "소개";)
Alex A.

2
예제를 기반으로 어떻게 보이는지 알지만 동작 인코딩은 여전히 ​​다소 혼란 스럽습니다. 첫 번째 / 마지막 이동을 제외하고 "초과 형"예를 보면 항상 대각선으로 이동합니다. 그러나 그것은 -매 턴마다 "앞으로"움직이는 것으로 정의되어 있습니다. 그러나 실제 움직임은 항상 대각선 왼쪽 두 개와 대각선 오른쪽 두 개입니다.
Reto Koradi

@RetoKoradi 나는 그것이 명백한 것은 아니지만 기본 아이디어는 모든 움직임으로 캐릭터의 너비를 오른쪽으로 여행한다는 것을 이해할 수 있습니다. 경로는 연속적으로 보여야하므로 오른쪽 및 왼쪽 회전 후 이전 / 다음 이동이 이전 경로 위 / 아래의 한 줄입니다.
Fatalize

@apsillers 둘 다 유효합니다. 올바르게 이해하면 답이 좋을 것입니다.
Fatalize

답변:


11

자바 스크립트 (ES6) 186 201

f=([...s])=>(g=(i,l,c=k=" ")=>s[i]!=k&&s[i]!="@"?0:(i-130)?(s[i]=c,([..."/-\\"].some((c,j)=>!((--j&l&&j!=l)||!g(i+33*(l||j)+1,j,c)))||!(s[i]=k))):(s[i]="@",!console.log(s.join(""))))(99)

실행 가능한 스 니펫 :

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><textarea cols="33" rows="7" id="t"></textarea><br><button><b>Solve &gt;&gt;&gt;</b></button><hr><button id="1">Normal</button> <button id="2">Hyperregular</button> <button id="3">Death Star core</button> <button id="4">Death Star trench</button> <button id="5">Asteroid cave</button><script>f=(function($__0){var $__2,$__3,$__4,$__5;s = $__4 = $__0.split("");return (g = (function(i, l) {var c = arguments[2] !== (void 0) ? arguments[2] : k = " ";return s[i] != k && s[i] != "@" ? 0 : (i - 130) ? (s[i] = c, ("/-\\".split("").some((function(c, j) {return !((--j & l && j != l) || !g(i + 33 * (l || j) + 1, j, c));})) || !(s[i] = k))) : (s[i] = "@",$("#t").val(s.join("")));}))(99);});$("button").click(function() {this.id?$("#t").val(inputs[this.id]):f($("#t").val());});inputs = [,`|   #####           #########  |\n| ######  #          ###   #   |\n|   # #  #  #  ####   #        |\n@              ##    ####       \n|#   #   #       ###   ##      |\n|##      ##      ####   #  #   |\n|####           ##### #   ##   |`,`|# # # # # # # # # # # # # # # |\n| # # # # # # # # # # # # # # #|\n|# # # # # # # # # # # # # # # |\n@ # # # # # # # # # # # # # #   \n|# # # # # # # # # # # # # # # |\n| # # # # # # # # # # # # # # #|\n|# # # # # # # # # # # # # # # |`,`|    #    #    #         #     |\n|         #    #    #          |\n|    #    #    #    #    #     |\n@    #    #    #    #    #      \n|    #    #         #    #     |\n|    #    #    #    #    #     |\n|    #         #    #    #     |`,`|##############################|\n|##############################|\n|##############################|\n@                               \n|##############################|\n|##############################|\n|##############################|`,`|### ##########################|\n|## # ############### ## ######|\n|# ###  ######## ### ## # #####|\n@ ###### ###### ### ## ###      \n|########  ### ### ## #########|\n|########## # ### ## ##########|\n|###########              #####|`];$("#t").val(inputs[1]);</script

이 함수는 줄 바꿈이있는 단일 문자열을 허용합니다. 이 함수는 ...연산자를 사용하여 문자열을 배열로 분할하고의 (x,y)좌표 인덱스를로 가져옵니다 (33 * y) + x.

이 기능은 재귀 적으로 실행되며 각 공간에 대해 다른 가능한 이동을 테스트합니다. 장애물이 발생하면 잘못된 값을 반환하고 최종 목표 공간에 도달하면를 반환합니다 true. (골프 코드에서는에 true의해 생성됩니다 !console.log(...).)

이 코드는 장시간의 우회전 이동을 사용하지 않지만 직선 이동으로 문장 부호를 표시합니다. 즉, 첫 번째 옵션이 아닌 아래 두 번째 옵션을 수행합니다.

\                       \
 \   (<= not this!)      -   (<= yes this!)
  \                       \

합법적 인 것처럼 보입니다 -. 턴 전후에 합법적으로 올 수 있기 때문에 왜 둘 다 동시에하지 않습니까? 마지막 움직임이 \있지만 @다음 과 같이 표시 될 때 특히 이상하게 보입니다 .

|  --#    #    #   ------#  -  |
| /  \    #    #  / #    \ / \ |
|/   #-   #    # /  #    #-   -|
     # \  #    #/   #    #     @
|    #  - # ----    #    #     |
|    #   \#/   #    #    #     |
|    #    -    #    #    #     |

내가 가장 좋아하는 불쾌한 골프 핵은 기본 인수 남용입니다 c=k=" ". 인수는 (i,l,c=" ")"문자열을 사용하는 말을 " "하기위한 c경우 f세 번째 인수가 제공되지 않습니다." 그러나을 수행하여 c=k=" "" c제공되지 않은 경우 " "전역 변수에 k저장 한 다음 해당 값도 저장하십시오 c"라고 말합니다. 재귀는 단일 인수로 시작하기 때문에 k항상 첫 번째 함수 호출에서 초기화됩니다.

온화한 골퍼

// `i` - index in the string we're working on
// `l` - move character for this space (`/`, `\`, or `-`)
search = (i,l,c)=>{

  // not an open space; nip this recursive branch
  if(s[i]!=" "&&s[i]!="@") { return 0; }

  // we made it! the 130th space is (31,3)
  if(i==130) {
      s[i]="@";
      console.log(s.join(""));
      return true;
  }

  // fill in space with move character or a blank
  // (the space is only to blank out the initial `@`)
  s[i] = c || " ";

  // iterate through the 3 options and recursively explore the map
  return ['/','-','\\'].some((c,j)=>{
    --j;
    // if last move was sideways, and this is the opposite move, skip it
    if(l && j && j!=l) { return 0; }

    // recursively call search function on space pointed to by this move or the last move
    return search(i+33*(l||j)+1, j, c);
  })

  // if the `some` call is false (i.e. all options fail for this space)
  // then blank out this space and return false
  || !(s[i]=" ");

}

@ vihan1086 맞아, 나는 골프를 할 때 그 공간을 완전히 놓쳤다. D : 배열에서 분할 문자열로 전환하는 것도 좋은 변화입니다. 감사. :) 또한 " "점수를 낮추는 몇 가지 다른 변경 사항 (현재 이동 문자를 함수 내에서 결정되는 대신 세 번째 인수로 만들고 변수에 저장 )을 만들었습니다.
apillers

7

C (전체 프로그램), 249 247 235 바이트

이것은 파일에서 입력을 읽고 stdout으로 결과를 출력하는 완전한 프로그램입니다. 파일 이름은 프로그램에 매개 변수로 전달됩니다.

char f[7][33];g(i,j,c){return(i<0|i>6|f[i][j]%32?0:j<31?c%45-2?g(i,j+1,c)||g(i+1,j+1,92)||g(i-1,j+1,47):g(i+c/30-2,j+1,c)||g(i+c/30-2,j+1,45):1)?f[i][j]=j?j-31?c:64:32:0;}main(int p,char**v){read(open(v[1],0),f,231);g(3,0,45);puts(f);}

언 골프 드 :

/* the field */
char f[7][33];

/* i - row
 * j - col
 * c - movement
 */
g(i,j,c)
{
    return
            /* if we're in bounds and not on an obstacle */
            (i >= 0 & i<7 & f[i][j] % 32 == 0 ?
                    /* if we haven't reached the end */
                    j < 31 ?
                            /* are we going straight ahead? */
                            c%45-2 ?
                                    /* try to go straight */
                                    g(i,j+1,c)
                                    /* try to turn right */
                                    || g(i+1,j+1,92)
                                    /* try to turn left */
                                    || g(i-1,j+1,47)
                            /* turning */
                            :
                                    /* try to keep turning */
                                    g(i+c/30-2,j+1,c)
                                    /* try to go straight */
                                    || g(i+c/30-2,j+1,45)
                    /* done */
                    :1 /* replace this with c==45 to better represent the last move being a turn */
            /* invalid move, fail */
            :0)
            /* add the correct movement to the field */
            ? f[i][j] = j ? j - 31 ? c : 64 : 32
            /* no path, much sads :( */
            :0;
}

main(int p,char*v[])
{
    /* read input file */
    read(open(v[1],0),f,231);

    /* calculate the path */
    g(3,0,45);

    /* print it out */
    puts(f);
}

산출:

$ ./a.out test.inp
|   #####           #########  |
| ######  #          ###   #   |
|   # #  #  #  ####   #      --|
 ------------- ##----####   /  @
|#   #   #    \ /### \ ##  /   |
|##      ##    - #### \ # /#   |
|####           ##### #---##   |

$ ./a.out test2.inp
|# # # # #-# # # # # #-# # # # |
| # # # #/#\# # # # #/#\# # # #|
|# # # #/# #\# # # #/# #\# # # |
 -# # #/# # #\# # #/# # #\# #  @
|#\# #/# # # #\# #/# # # #\# #/|
| #\#/# # # # #\#/# # # # #\#/#|
|# #-# # # # # #-# # # # # #-# |

$ ./a.out test3.inp
|    #    #    #   ------#     |
|    -    #    #  / #    \     |
|   /#\   #    # /  #    #\    |
 --- # \  #    #/   #    # \   @
|    #  \ #    /    #    #  \ /|
|    #   \#   /#    #    #   - |
|    #    ---- #    #    #     |

$ ./a.out test4.inp
|##############################|
|##############################|
|##############################|
 ------------------------------@
|##############################|
|##############################|
|##############################|

$ ./a.out test5.inp
|###-##########################|
|##/#\############### ##-######|
|#/###--######## ### ##/#\#####|
 -######\###### ### ##/###-----@
|########--### ### ##/#########|
|##########\# ### ##/##########|
|###########--------      #####|

첫 번째 테스트에서 끝점을 놓친 것 같습니다.
레토 코라디

@RetoKoradi -다음에 a \가 있지만에 \의해 덮여 @있습니다. (나의 프로그램도 같은 일을한다.)
apillers

1
@RetoKoradi 이것의 이전 반복은 그 경우를 더 잘 처리했습니다. +4 바이트입니다. 나는 apsillers의 솔루션이 비슷하게 작동하는 것을 발견하여 공간을 절약하기로 결정했습니다.
Cole Cameron

내가 참조. 그것은 나에게는 옳아 보이지 않지만 허용되는 것을 결정하는 것은 OP에 달려 있습니다. 나는 그들이 움직임이 어떻게 표현되는지에 대한 자유를주는 것을 보았다. 처음부터 명확하고 독특한 정의를보고 싶었습니다. 그것은 재미있는 문제처럼 보였지만 모호함에 대해서는 그리 흥미롭지 않습니다.
Reto Koradi

3

공통 리스프, 303 바이트

이 도전에 많은 즐거움을 안겨준 것은 내가 한 첫 번째 골프 골 과제입니다. 기본적으로 끝 위치에 도달 할 때까지 모든 실행 가능한 이동을 시도하는 간단한 재귀 함수가 있습니다.

골프 / 최소화

(let((s(open "i"))(n nil)(f(make-string 231)))(read-sequence f s)(labels((r(p s u d)(and(< 0 p 224)(find(aref f p)" @")(setf(aref f p)(cond((= 130 p)#\@)((or(unless d(r(- p 32)#\/ t n))(unless u(r(+ p 34)#\\ n t))(r(+ p(cond(u -32)(d 34)(t 1)))#\- n n))s)((return-from r)))))))(r 99 #\- n n)(princ f)))

작업 디렉토리 의 파일 i 에서 입력을 읽습니다 . 여전히 개선의 여지가 있다고 확신합니다.

일반 코드

(defun run-test (file)
  (let ((stream (open file)) ;;should use with-open-file for autoclose..
        (no nil) ;; alias for brevity
        (field (make-string 231)))
    (read-sequence field stream)
    (labels ((doit (pos sym going-up going-down)
               (and
                 (< 0 pos 224)
                 (find (aref field pos) " @")
                 (setf (aref field pos)
                       (cond
                         ((= 130 pos) #\@)
                         ((or
                            (unless going-down (doit (- pos 32) #\/ t no))
                            (unless going-up (doit (+ pos 34) #\\ no t))
                            (doit (+ pos (cond (going-up -32)
                                               (going-down 34)
                                               (t 1)))
                                  #\- no no))
                          sym)
                         ((return-from doit)))))))
      (doit 99 #\- no no)
      (princ field)
      nil)))

샘플 출력

|   #####       --  #########  |
| ######  #    /  \  ###   # - |
|   # #  #  # /####\  #     / \|
--   -       / ##   \####  /   @
|#\ /#\  #  /    ### \ ## /    |
|##-   \ ##/     #### \ #/ #   |
|####   ---     ##### #-- ##   |

|  --#    #    #   --    #-    |
| /  \    #    #  / #\   / \   |
|/   #\   #    # /  # \ /#  \  |
-    # \  #    #/   #  - #   \ @
|    #  \ # ----    #    #    -|
|    #   \#/   #    #    #     |
|    #    -    #    #    #     |

|# #-# # # # # #-# # # # # #-# |
| #/#\# # # # #/#\# # # # #/#\#|
|#/# #\# # # #/# #\# # # #/# #\|
--# # #\# # #/# # #\# # #/# #  @
|# # # #\# #/# # # #\# #/# # # |
| # # # #\#/# # # # #\#/# # # #|
|# # # # #-# # # # # #-# # # # |

2

액션 스크립트 3, 364 바이트

나는 이것을 두 가지 기능으로 나누었다. 하나는 배열을 배열의 배열로 바꾸고 다른 하나는 비행 경로를 계산하는 것입니다.

function m(f){for(var i=0;i<f.length;i++){f[i]=f[i].split("");}n(f,0,3,0);return f;}function n(f,x,y,m){var P=f[y][x],X=x+1,A=y-1,B=y,C=y+1,T=true,F=false,E='-';if (y<0||y>6||P=='#'||P=='|')return F;if (x==31){f[y][x]='@';return T;}if(m<0&&y>0){B=A;C=9;E='/';}else if(m>0&&y<6){A=9;B=C;E='\\';}if (n(f,X,B,0)||n(f,X,A,-1)||n(f,X,C,1)){f[y][x]=E;return T;return F;}

하나의 샘플 소행성 필드가 정의 된 프로그램의 비 골프 버전 :

package
{
    import flash.display.Sprite;

    public class AsteroidNavigator extends Sprite
    {
        var field:Array;
        public function AsteroidNavigator()
        {
            field = [
"|   #####           #########  |",
"| ######  #          ###   #   |",
"|   # #  #  #  ####   #        |",
"@              ##    ####       ",
"|#   #   #       ###   ##      |",
"|##      ##      ####   #  #   |",
"|####           ##### #   ##   |"];
            m(field);
            printField();
        }

        function m(f){
            for(var i=0;i<f.length;i++){
                f[i]=f[i].split("");\
            }
            n(f,0,3,0);
            return f;
        }

        private function n(field,x,y,m) {
            var C = field[y][x];
            if (x > 31 || C == '#' || C == '|') {
                return false;
            }
            if (x == 31 && y == 3) {
                field[y][x] = '@';
                return true;
            }
            if (m == 0) {
                if (n(x+1, y, 0) || ((y>0) && n(x+1, y-1, -1)) || ((y<6) && n(x+1, y+1, 1))) {
                field[y][x] = '-';
                return true;
                }
            } else if ((m<0) && (y>0)) {
                if ((n(x+1, y-1, -1) || n(x+1, y-1, 0))) {
                    field[y][x] = '/';
                    return true;
                }
            } else if ((m>0) && (y<6)) {
                if ((n(x+1, y+1, 1) || n(x+1, y+1, 0))) {
                    field[y][x] = '\\';
                    return true;
                }
            }
            return false;
        }

        private function printField() {
            var sb = "";
            for each (var row:Array in field) {
                sb += row.join("") + "\n";
            }
            trace(sb);
        }
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.