Sácame de aquí

12

Desafío

Dado el tamaño de la cuadrícula, las posiciones de los obstáculos, la posición del jugador y la posición del objetivo, su tarea es encontrar un camino para que el jugador llegue al objetivo y evitar los obstáculos al mismo tiempo (si es necesario).

ingrese la descripción de la imagen aquí


Entrada

  • N : tamaño de cuadrículaN x N
  • P : posición del jugador[playerposx, playerposy]
  • T : posición del objetivo[targetposx, targetposy]
  • O : Posiciones de obstáculos[[x1, y1], [x2, y2],...,[xn, yn]]

Salida

Ruta : Un jugador de ruta puede usar para alcanzar el objetivo.[[x1, y1], [x2, y2],...,[xn, yn]]


Reglas

  1. El punto [0,0]está en la esquina superior izquierda de la cuadrícula.
  2. La posición del jugador siempre estará en el lado izquierdo de la cuadrícula.
  3. La posición del objetivo siempre estará en el lado derecho de la cuadrícula.
  4. La cuadrícula siempre tendrá al menos un obstáculo.
  5. Puede suponer que ningún obstáculo se superpone a la posición del jugador o del objetivo.
  6. No necesariamente necesita encontrar la ruta mínima.
  7. El jugador solo puede moverse hacia la izquierda, derecha, arriba y abajo, no en diagonal.
  8. Puede tomar la entrada de cualquier manera conveniente.
  9. Puede suponer que siempre existirá un camino para que el jugador llegue al objetivo.
  10. Obviamente, para cada entrada existen múltiples rutas válidas, elija una.
  11. Suponga N > 2que la cuadrícula será al menos 3 x 3.

Ejemplos

Entrada: 9, [6, 0], [3, 8], [[0, 5], [2, 2], [6, 4], [8, 2], [8, 7]]
Posible salida:[[6, 0], [6, 1], [6, 2], [6, 3], [5, 3], [5, 4], [5, 5], [5, 6], [5, 7], [5, 8], [4, 8], [3, 8]]

Entrada: 6, [1, 0], [3, 5], [[1, 2], [2, 5], [5, 1]]
Posible salida:[[1, 0], [1, 1], [2, 1], [2, 2], [2, 3], [2, 4], [3, 4], [3, 5]]


Nota

Tenga en cuenta que Xes para filas y Ypara cols. No los confunda con las coordenadas en una imagen.

Editar

Como señaló @digEmAll, debido a las reglas #2y #3, playerY = 0y targetY = N-1. Entonces, si lo desea, puede tomar solo como entrada playerXy y targetX(si eso acorta su código).

DimChtz
fuente
1
"La posición del jugador siempre estará en el lado izquierdo y el objetivo en el lado derecho": ¿significa esto que jugador-y = 0 y objetivo-y = N-1? Si es así, ¿podemos aceptar la coordenada x (un número) para jugador y objetivo?
digEmAll
1
@digEmAll Buen punto. Honestamente, no pensé en esto y sí, puedes editarlo.
DimChtz
Relacionado pero más fácil. Relacionado pero más difícil.
user202729
¿El camino tiene que ser de principio a fin, o puede estar en orden inverso?
kamoroso94
1
@ kamoroso94 Sí, comenzar a apuntar (terminar) :)
DimChtz

Respuestas:

5

JavaScript (ES6), 135 bytes

Toma entrada como (width, [target_x, target_y], obstacles)(source_x, source_y), donde los obstáculos son una serie de cadenas en "X,Y"formato.

Devuelve una matriz de cadenas en "X,Y"formato.

(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

Pruébalo en línea!

Comentado

(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
Arnauld
fuente
5

R , 227 bytes

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)}

Pruébalo en línea!

No es realmente corto y definitivamente no da el camino más corto (por ejemplo, verifique el primer ejemplo).
Básicamente realiza una búsqueda recursiva de profundidad primero y se detiene tan pronto como se alcanza el objetivo, imprimiendo la ruta.

Gracias a JayCe por la mejora en el formato de salida

digEmAll
fuente
+1 Me gusta la forma en que imprime la salida (no la típica lista aburrida de listas) :)
DimChtz
@DimChtz: bueno, gracias ... pero esa es la función auxiliar, la función de código de golf solo imprime una lista de coordenadas x1 y1 x2 y2 ... xn yn: D
digEmAll
1
Sí, lo sé: P pero sigue siendo agradable.
DimChtz
1
de acuerdo con @DimChtz ... y creo que se ve aún mejor si en write(t(mx),1,N)lugar de hacerlo print:)
JayCe
@ JayCe: buena idea, ¡cambió!
digEmAll
4

Python 2 , 151 149 bytes

N,s,e,o=input()
P=[[s]]
for p in P:x,y=k=p[-1];k==e>exit(p);P+=[p+[[x+a,y+b]]for a,b in((0,1),(0,-1),(1,0),(-1,0))if([x+a,y+b]in o)==0<=x+a<N>y+b>-1]

Pruébalo en línea!

ovs
fuente
3

Haskell , 133 131 130 bytes

  • -1 byte gracias a 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])

Pruébalo en línea! (con algunos casos de prueba)

Una función que !toma como entrada

  • n :: Int tamaño de la cuadrícula
  • p :: [Int] posición del jugador como una lista [xp, yp]
  • o :: [[Int]] posición de obstáculos como una lista [[x1, y1], [x2, y2], ...]
  • t :: [[[Int]]](implícita) la posición del objetivo como una lista [[[xt, yt]]](lista triple solo por conveniencia)

y devolver una ruta válida como una lista [[xp, yp], [x1, y1], ..., [xt, yt]].

Como beneficio adicional, encuentra (uno de) los caminos más cortos y funciona para la posición de cualquier jugador y objetivo. Por otro lado, es muy ineficiente (pero los ejemplos proporcionados se ejecutan en un período de tiempo razonable).

Explicación

(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]]

La expresión aparentemente oscura [id, map (+ 1)] <*> [[x - 1,y], [x, y - 1]]es solo una versión "golfy" (-1 byte) de [[x + 1, y], [x, y + 1], [x - 1, y], [x, y - 1]].

Delfad0r
fuente
2
Bienvenido a PPCG! Buena primera respuesta!
Arnauld
1
@Arnauld ¡Gracias! De hecho, pasé varias horas tratando de exprimir algunos bytes de mi solución solo para superar tu 135 ^^
Delfad0r
1
Buen golf! Puede guardar un byte utilizando un operador en lugar de una función: ¡ Pruébelo en línea!
ბიმო
@BWO Gracias por el consejo. Soy nuevo aquí, así que hay muchos trucos de los que nunca he oído hablar
Delfad0r
1
Por cierto. Hay una sección con consejos para Haskell en particular donde puedes encontrar este y muchos más trucos. Ah, y siempre hay chat también: De mónadas y hombres
ბიმო
1

Retina 0.8.2 , 229 bytes

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

Pruébalo en línea! No estoy seguro si el formato de E / S califica. Explicación:

.
$&$&

Duplicar cada celda. La copia izquierda se utiliza como área de trabajo temporal.

@@
s@

Marque el inicio del laberinto como visitado.

##
.#

Marque el final del laberinto como vacío.

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

Si bien existen celdas de trabajo disponibles, apúntelas a celdas adyacentes visitadas previamente.

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

Trace el camino desde la salida hasta el inicio utilizando las celdas de trabajo como guía.

.(.)
$1

Eliminar las celdas de trabajo.

Neil
fuente
1

JavaScript, 450 bytes

Toma entrada como (n, {playerx, playery}, {targetx, targety}, [{obstaclex, obstacley}]). Devuelve una matriz de {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;}

Aquí hay una versión no ofuscada en mi desastre:

// 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;
}
MinerBigWhale
fuente