나를 여기에서 꺼내 줘


12

도전

그리드 크기, 장애물 위치, 플레이어 위치 및 목표 위치가 주어지면 플레이어가 목표에 도달 할 수있는 경로를 찾고 동시에 장애물을 피해야합니다 (필요한 경우).

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


입력

  • N : 격자 크기N x N
  • P : 선수 위치[playerposx, playerposy]
  • T : 목표 위치[targetposx, targetposy]
  • O : 장애물의 위치[[x1, y1], [x2, y2],...,[xn, yn]]

산출

경로 : 경로 플레이어가 목표에 도달하는 데 사용할 수 있습니다[[x1, y1], [x2, y2],...,[xn, yn]]


규칙

  1. [0,0]은 그리드의 왼쪽 상단에 있습니다.
  2. 플레이어의 위치는 항상 그리드의 왼쪽에 있습니다.
  3. 대상의 위치는 항상 그리드의 오른쪽에 있습니다.
  4. 그리드에는 항상 하나 이상의 장애물이 있습니다.
  5. 장애물이 플레이어 나 목표 위치와 겹치지 않는다고 가정 할 수 있습니다.
  6. 반드시 최소 경로를 찾을 필요는 없습니다.
  7. 플레이어는 대각선이 아닌 왼쪽, 오른쪽, 위, 아래 만 움직일 수 있습니다.
  8. 편리한 방법으로 입력을받을 수 있습니다.
  9. 플레이어가 목표를 달성하기위한 경로가 항상 존재한다고 가정 할 수 있습니다.
  10. 분명히, 각 입력에 대해 유효한 경로가 여러 개 존재하면 하나를 선택하십시오.
  11. N > 2그리드가 최소한 이라고 가정하십시오 3 x 3.

입력 : 9, [6, 0], [3, 8], [[0, 5], [2, 2], [6, 4], [8, 2], [8, 7]]
가능한 출력 :[[6, 0], [6, 1], [6, 2], [6, 3], [5, 3], [5, 4], [5, 5], [5, 6], [5, 7], [5, 8], [4, 8], [3, 8]]

입력 : 6, [1, 0], [3, 5], [[1, 2], [2, 5], [5, 1]]
가능한 출력 :[[1, 0], [1, 1], [2, 1], [2, 2], [2, 3], [2, 4], [3, 4], [3, 5]]


노트

공지 X행을하고있다 YCOLS을 위해. 이미지의 좌표와 혼동하지 마십시오.

편집하다

로 @digEmAll 인해 규칙을 지적 #2하고 #3, playerY = 0하고 targetY = N-1. 따라서 원하는 경우 입력으로 만 사용할 수 있습니다 ( playerX그리고 targetX코드가 더 짧아지면).


1
"플레이어 위치는 항상 왼쪽에 있고 오른쪽에 목표입니다": 이것은 player-y = 0이고 target-y = N-1입니까? 그렇다면 플레이어와 대상에 대한 x 좌표 (하나의 숫자) 만 받아 들일 수 있습니까?
digEmAll

1
@digEmAll 좋은 지적입니다. 솔직히, 나는 이것을 생각하지 않았고 네가 이것을 편집 할 수 있습니다.
DimChtz

관련이 있지만 더 쉽습니다. 관련이 있지만 어렵습니다.
user202729

경로는 처음부터 끝까지되어야합니까 아니면 반대 순서 일 수 있습니까?
kamoroso94

1
@ kamoroso94 예, :) (마감)을 대상으로 시작
DimChtz

답변:


5

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

입력을로 가져 옵니다. (width, [target_x, target_y], obstacles)(source_x, source_y)여기서 장애물"X,Y"형식 의 문자열 배열입니다 .

"X,Y"형식 의 문자열 배열을 반환 합니다.

(n,t,o)=>g=(x,y,p=[],P=[...p,v=x+','+y])=>v==t?P:~x&~y&&x<n&y<n&[...o,...p].indexOf(v)<0&&[0,-1,0,1].some((d,i)=>r=g(x+d,y-~-i%2,P))&&r

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

댓글

(n, t, o) =>              // n = width of maze, t[] = target coordinates, o[] = obstacles
  g = (                   // g() = recursive search function taking:
    x, y,                 //   (x, y) = current coordinates of the player
    p = [],               //   p[] = path (a list of visited coordinates, initially empty)
    P = [                 //   P[] = new path made of:
      ...p,               //     all previous entries in p
      v = x + ',' + y     //     the current coordinates coerced to a string v = "x,y"
    ]                     //
  ) =>                    //
    v == t ?              // if v is equal to the target coordinates:
      P                   //   stop recursion and return P
    :                     // else:
      ~x & ~y             //   if neither x nor y is equal to -1
      && x < n & y < n    //   and both x and y are less than n
      & [...o, ...p]      //   and neither the list of obstacles nor the path
        .indexOf(v) < 0   //   contains a position equal to the current one:
      && [0, -1, 0, 1]    //     iterate on all 4 possible directions
        .some((d, i) =>   //     for each of them:
          r = g(          //       do a recursive call with:
            x + d,        //         the updated x
            y - ~-i % 2,  //         the updated y
            P             //         the new path
          )               //       end of recursive call
        ) && r            //     if a solution was found, return it

5

R , 227 바이트

function(N,P,G,O){M=diag(N+2)*0
M[O+2]=1
b=c(1,N+2)
M[row(M)%in%b|col(M)%in%b]=1
H=function(V,L){if(all(V==G+2))stop(cat(L))
M[t(V)]=2
M<<-M
for(i in 0:3){C=V+(-1)^(i%/%2)*(0:1+i)%%2
if(!M[t(C)])H(C,c(L,C-2))}}
try(H(P+2,P),T)}

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

실제로는 짧지 않고 가장 짧은 경로를 제공하지 않습니다 (예 : 첫 번째 예 확인).
기본적으로 재귀 깊이 우선 검색을 수행하고 대상에 도달하자 마자 경로를 인쇄합니다.

출력 형식을 개선 한 JayCe에게 감사드립니다.


+1 나는 당신이 출력물을 출력하는 방식이 마음에 든다 (일반적인 지루한리스트는 제외) :)
DimChtz

@DimChtz : 물론 감사하지만 ... 헬퍼 함수의 코드 골프 기능은 좌표의 목록을 출력 x1 y1 x2 y2 ... xn ynD :
digEmAll

1
그렇습니다, 나는 알고 있습니다 : P 그러나 여전히 좋습니다.
DimChtz

1
@DimChtz에 동의합니다 ... 그리고 당신 write(t(mx),1,N)printing 대신에 더 좋아 보인다고 생각 합니다 :)
JayCe

@JayCe : 좋은 생각, 변화!
digEmAll


3

하스켈 , 133 (131) 130 바이트

  • BWO 덕분에 -1 바이트
(n!p)o=head.(>>=filter(elem p)).iterate(\q->[u:v|v@([x,y]:_)<-q,u<-[id,map(+1)]<*>[[x-1,y],[x,y-1]],all(/=u)o,x`div`n+y`div`n==0])

온라인으로 사용해보십시오! (몇 가지 테스트 케이스 포함)

!입력으로받는 기능

  • n :: Int 격자의 크기
  • p :: [Int] 목록으로 선수의 위치 [xp, yp]
  • o :: [[Int]] 장애물은 목록으로 위치 [[x1, y1], [x2, y2], ...]
  • t :: [[[Int]]](암시 적) 대상의 목록 위치 [[[xt, yt]]](편의를 위해 트리플 목록)

유효한 경로를 목록으로 반환합니다 [[xp, yp], [x1, y1], ..., [xt, yt]].

보너스로, 가장 짧은 경로를 발견하고 모든 플레이어와 대상의 위치에서 작동합니다. 반면에, 그것은 매우 비효율적입니다 (그러나 제공된 예제는 합리적인 시간 내에 실행됩니다).

설명

(n ! p) o =                                                         -- function !, taking n, p, o and t (implicit by point-free style) as input
    head .                                                          -- take the first element of
    (>>= filter (elem p)) .                                         -- for each list, take only paths containing p and concatenate the results
    iterate (                                                       -- iterate the following function (on t) and collect the results in a list
        \q ->                                                       -- the function that takes a list of paths q...
            [u : v |                                                -- ... and returns the list of paths (u : v) such that:
                v@([x, y] : _) <- q,                                -- * v is an element of q (i.e. a path); also let [x, y] be the first cell of v
                u <- [id, map (+ 1)] <*> [[x - 1,y], [x, y - 1]],   -- * u is one of the neighbouring cells of [x, y]
                all (/= u) o,                                       -- * u is not an obstacle
                x `div` n + y `div` n == 0                          -- * [x, y] is inside the grid
            ]
    )

iteratekk1[[xt, yt]]

분명히 모호한 표현 [id, map (+ 1)] <*> [[x - 1,y], [x, y - 1]]은 "골프"(-1 바이트) 버전입니다 [[x + 1, y], [x, y + 1], [x - 1, y], [x, y - 1]].


2
PPCG에 오신 것을 환영합니다! 좋은 첫 답변!
Arnauld

1
@Arnauld 감사합니다! 실제로 몇 시간 동안 내 솔루션에서 몇 바이트를 짜서 135를 이길 수
있었습니다

1
좋은 골프! 함수 대신 연산자를 사용하여 1 바이트를 저장할 수 있습니다. 온라인으로 사용해보십시오!
ბიმო

@BWO 팁 주셔서 감사합니다. 나는 여기에 처음이므로, 들어 본 적이없는 많은 트릭이 있습니다.
Delfad0r

1
Btw. Haskell에 대한 팁 이 포함 된 섹션 있으며 여기에는 더 많은 유용한 정보가 있습니다. : 아 너무 채팅 항상 거기 모나드와 남자의
ბიმო

1

레티 나 0.8.2 , 229 바이트

.
$&$&
@@
s@
##
.#
{`(\w.)\.
$1l
\.(.\w)
r$1
(?<=(.)*)\.(?=.*¶(?<-1>.)*(?(1)$)\w)
d
}`\.(?=(.)*)(?<=\w(?(1)$)(?<-1>.)*¶.*)
u
+T`.`#`.(?=(.)*)(?<=d#(?(1)$)(?<-1>.)*¶.*)|(?<=(.)*.).(?=.*¶(?<-2>.)*(?(2)$)u#)|(?<=#r).|.(?=l#)
.(.)
$1

온라인으로 사용해보십시오! I / O 형식이 적합한 지 확실하지 않습니다. 설명:

.
$&$&

각 셀을 복제하십시오. 왼쪽 사본은 임시 작업 영역으로 사용됩니다.

@@
s@

방문한 미로의 시작을 표시하십시오.

##
.#

미로의 끝을 비워 둡니다.

{`(\w.)\.
$1l
\.(.\w)
r$1
(?<=(.)*)\.(?=.*¶(?<-1>.)*(?(1)$)\w)
d
}`\.(?=(.)*)(?<=\w(?(1)$)(?<-1>.)*¶.*)
u

사용 가능한 작업 셀이 있지만 이전에 방문한 인접 셀을 가리 킵니다.

+T`.`#`.(?=(.)*)(?<=d#(?(1)$)(?<-1>.)*¶.*)|(?<=(.)*.).(?=.*¶(?<-2>.)*(?(2)$)u#)|(?<=#r).|.(?=l#)

작업 셀을 가이드로 사용하여 출구에서 시작까지의 경로를 추적하십시오.

.(.)
$1

작업 셀을 삭제하십시오.


1

자바 스크립트, 450 바이트

로 입력을 (n, {playerx, playery}, {targetx, targety}, [{obstaclex, obstacley}])받습니다. 의 배열을 반환합니다 {hopx, hopy}.

j=o=>JSON.stringify(o);l=a=>a.length;c=(a,o)=>{let i=l(a);while(i>0){i--;if(j(a[i])==j(o)){return 1;}}return 0;}h=(p,t,o)=>{if(p.y<t.y&&!c(o,{x:p.x,y:p.y+1})){return{x:p.x,y:p.y+1};}if(p.y>t.y&&!c(o,{x:p.x,y:p.y-1})){return{x:p.x,y:p.y-1};}if(p.x<t.x&&!c(o,{x:p.x+1,y:p.y})){return{x:p.x+1,y:p.y};}if(p.x>t.x&&!c(o,{x:p.x-1,y:p.y})){return{x:p.x-1,y:p.y};}return t;}w=(n,p,t,o)=>{let r=[];r.push(p);while(j(p)!==j(t)){p=h(p,t,o);r.push(p);}return r;}

여기 혼란에 빠지지 않은 버전이 있습니다.

// defining some Array's function for proper comparaisons
json = (object) => { return JSON.stringify(object) };
length = (array) => { return array.length; }
contains = (array, object) => {
    let i = length(array);
    while (i > 0) {
    i--;
        if (json(array[i]) == json(object)) { return true; }
    }
    return false;
}
//return next found hop
getNextHop = (player, target, obstacles) => {
    //uggly serie of conditions
    //check where do we have to go and if there is an obstacle there
    if(player.y<target.y && !contains(obstacles, [x:player.x, y:player.y+1])) { return [x:player.x, y:player.y+1]; }
    if(player.y>target.y && !contains(obstacles, [x:player.x, y:player.y-1])) { return [x:player.x, y:player.y-1]; }
    if(player.x<target.x && !contains(obstacles, [x:player.x+1, y:player.y])) { return [x:player.x+1, y:player.y]; }
    if(player.x>target.x && !contains(obstacles, [x:player.x-1, y:player.y])) { return [x:player.x-1, y:player.y]; }
    return target;
}
//return found path
getPath = (gridsize, player, target, obstacles) => {
    let path = [];
    path.push(player);
    //while player is not on target
    while(json(player)!=json(target)) {
        player = getNextHop(player, target, obstacles); //gridsize is never used as player and target are in the grid boundaries
        path.push(player);
    }
    return path;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.