Забери мене звідси


12

Виклик

Враховуючи розмір сітки, позиції перешкод, позицію гравця та цільову позицію, ваше завдання - знайти шлях для гравця, щоб дістатися до цілі та одночасно уникати перешкод (якщо це необхідно).

введіть тут опис зображення


Вхідні дані

  • N : розмір сіткиN x N
  • П : Позиція гравця[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це для рядків і Yдля знаків. Не плутайте їх з координатами на зображенні.

Редагувати

Як зазначав @digEmAll, через правила #2і #3, playerY = 0та targetY = N-1. Отже, якщо ви хочете, ви можете взяти за вхід лише playerXі і targetX(якщо це робить ваш код коротшим).


1
"Позиція гравця завжди буде зліва, а ціль - з правого боку": чи це означає, що гравець-у = 0 і ціль-у = Н-1? Якщо так, то чи можемо ми просто прийняти координату x (одне число) для гравця та цілі?
digEmAll

1
@digEmAll Добре. Чесно кажучи, я не думав про це, і так, ви можете це відредагувати.
DimChtz

Пов’язане, але простіше. Пов'язані, але важчі.
користувач202729

Чи має бути шлях від початку до кінця, чи це може бути у зворотному порядку?
kamoroso94

1
@ kamoroso94 Так, почніть націлювати (фінішу) :)
DimChtz

Відповіді:


5

JavaScript (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 yn: D
digEmAll

1
Так, я знаю: P, але все одно приємно.
DimChtz

1
погоджуюся з @DimChtz ... і я думаю, що це виглядає ще краще, якщо ти write(t(mx),1,N)замість printing :)
JayCe

@JayCe: гарна ідея, змінено!
digEmAll


3

Haskell , 133 131 130 байт

  • -1 байт завдяки BWO
(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
            ]
    )

Ця функція виконує рекурсивний BFS через iterate, починаючи з цілі та досягаючи початкової позиції гравця. Шляхи довжини одержуються шляхом додавання відповідних комірок до дійсних шляхів довжиною , починаючи з єдиного допустимого шляху довжиною 1, тобто шляху .k - 1kk1[[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! Приємна перша відповідь!
Арнольд

1
@Arnauld Дякую! Я фактично провів кілька годин, намагаючись вичавити кілька байт з мого рішення, щоб просто побити ваші 135 ^^
Delfad0r

1
Гарний гольф! Ви можете зберегти один байт, скориставшись оператором замість функції: Спробуйте в Інтернеті!
ბიმო

@BWO Дякую за пораду. Я тут новачок, тому є багато хитрощів, про які я ніколи не чув
Delfad0r

1
Btw. є розділ із порадами щодо Haskell, зокрема, де ви можете знайти це та багато інших хитрощів. О, і завжди також балакають: Monads and Men
ბიმო

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

Спробуйте в Інтернеті! Не впевнений, чи відповідає формату вводу-виводу. Пояснення:

.
$&$&

Дублювати кожну клітинку. Ліва копія використовується як тимчасова робоча зона.

@@
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

JavaScript, 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;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.