Faites moi sortir d'ici

12

Défi

Compte tenu de la taille de la grille, de la position des obstacles, de la position du joueur et de la position cible, votre tâche consiste à trouver un chemin pour que le joueur atteigne la cible et évite les obstacles en même temps (si nécessaire).

entrez la description de l'image ici


Contribution

  • N : taille de la grilleN x N
  • P : Position du joueur[playerposx, playerposy]
  • T : Position de la cible[targetposx, targetposy]
  • O : Positions des obstacles[[x1, y1], [x2, y2],...,[xn, yn]]

Production

Chemin : un chemin que le joueur peut utiliser pour atteindre la cible[[x1, y1], [x2, y2],...,[xn, yn]]


Règles

  1. Le point se [0,0]trouve dans le coin supérieur gauche de la grille.
  2. La position du joueur sera toujours sur le côté gauche de la grille.
  3. La position de la cible sera toujours sur le côté droit de la grille.
  4. La grille aura toujours au moins un obstacle.
  5. Vous pouvez supposer qu'aucun obstacle ne chevauche le joueur ou la position cible.
  6. Vous n'avez pas nécessairement besoin de trouver le chemin min.
  7. Le joueur ne peut se déplacer qu'à gauche, à droite, en haut et en bas et non en diagonale.
  8. Vous pouvez prendre l'entrée de n'importe quelle manière pratique.
  9. Vous pouvez supposer qu'il existe toujours un chemin pour que le joueur atteigne la cible.
  10. Évidemment, pour chaque entrée, il existe plusieurs chemins valides, choisissez-en un.
  11. Supposons N > 2que la grille soit au moins 3 x 3.

Exemples

Entrée: 9, [6, 0], [3, 8], [[0, 5], [2, 2], [6, 4], [8, 2], [8, 7]]
Sortie possible:[[6, 0], [6, 1], [6, 2], [6, 3], [5, 3], [5, 4], [5, 5], [5, 6], [5, 7], [5, 8], [4, 8], [3, 8]]

Entrée: 6, [1, 0], [3, 5], [[1, 2], [2, 5], [5, 1]]
Sortie possible:[[1, 0], [1, 1], [2, 1], [2, 2], [2, 3], [2, 4], [3, 4], [3, 5]]


Remarque

Notez que Xc'est pour les lignes et Ypour les cols. Ne les confondez pas avec les coordonnées d'une image.

Éditer

Comme l'a souligné @digEmAll, en raison des règles #2et #3, playerY = 0et targetY = N-1. Donc, si vous le souhaitez, vous pouvez prendre en entrée uniquement playerXet et targetX(si cela rend votre code plus court).

DimChtz
la source
1
"La position du joueur sera toujours sur le côté gauche et la cible sur le côté droit": cela signifie-t-il que le joueur-y = 0 et la cible-y = N-1? Si oui, pouvons-nous simplement accepter la coordonnée x (un numéro) pour le joueur et la cible?
digEmAll
1
@digEmAll Bon point. Honnêtement, je n'y ai pas pensé et oui, vous pouvez le modifier.
DimChtz
Associé mais plus facile. Lié mais plus difficile.
user202729
Le chemin doit-il être du début à la fin, ou peut-il être dans l'ordre inverse?
kamoroso94
1
@ kamoroso94 Oui, commencer à viser (terminer) :)
DimChtz

Réponses:

5

JavaScript (ES6), 135 octets

Prend l'entrée comme (width, [target_x, target_y], obstacles)(source_x, source_y), où obstacles est un tableau de chaînes au "X,Y"format.

Renvoie un tableau de chaînes au "X,Y"format.

(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

Essayez-le en ligne!

Commenté

(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
la source
5

R , 227 octets

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

Essayez-le en ligne!

Pas vraiment court, et ne donnant certainement pas le chemin le plus court (par exemple, vérifiez le premier exemple).
Il effectue essentiellement une recherche récursive en profondeur et s'arrête dès que la cible est atteinte, imprimant le chemin.

Merci à JayCe pour l'amélioration du formatage de sortie

digEmAll
la source
+1 J'aime la façon dont vous imprimez la sortie (pas la liste ennuyeuse typique de listes) :)
DimChtz
@DimChtz: bien merci mais ... c'est la fonction d'aide, la fonction code-golf imprime juste une liste de coordonnées x1 y1 x2 y2 ... xn yn: D
digEmAll
1
Oui, je sais: P mais toujours sympa.
DimChtz
1
d'accord avec @DimChtz ... et je pense que cela semble encore mieux si vous write(t(mx),1,N)au lieu de printing :)
JayCe
@JayCe: bonne idée, changé!
digEmAll
4

Python 2 , 151 149 octets

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]

Essayez-le en ligne!

ovs
la source
3

Haskell , 133 131 130 octets

  • -1 octet grâce à 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])

Essayez-le en ligne! (avec quelques tests)

Une fonction !prenant en entrée

  • n :: Int taille de la grille
  • p :: [Int] position du joueur en tant que liste [xp, yp]
  • o :: [[Int]] position des obstacles sous forme de liste [[x1, y1], [x2, y2], ...]
  • t :: [[[Int]]](implicite) la position de la cible en tant que liste [[[xt, yt]]](triple liste juste pour plus de commodité)

et renvoyer un chemin valide sous forme de liste [[xp, yp], [x1, y1], ..., [xt, yt]].

En prime, il trouve (l'un des) chemin (s) le plus court (s) et fonctionne pour la position de n'importe quel joueur et cible. En revanche, c'est très inefficace (mais les exemples fournis fonctionnent dans un laps de temps raisonnable).

Explication

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

L'expression apparemment obscure [id, map (+ 1)] <*> [[x - 1,y], [x, y - 1]]n'est qu'une version "golfy" (-1 octet) de [[x + 1, y], [x, y + 1], [x - 1, y], [x, y - 1]].

Delfad0r
la source
2
Bienvenue chez PPCG! Belle première réponse!
Arnauld
1
@Arnauld Merci! En fait, j'ai passé plusieurs heures à essayer d'extraire quelques octets de ma solution juste pour battre votre 135 ^^
Delfad0r
1
Beau golf! Vous pouvez enregistrer un octet en utilisant un opérateur au lieu d'une fonction: Essayez-le en ligne!
ბიმო
@BWO Merci pour l'astuce. Je suis nouveau ici, donc il y a beaucoup de trucs dont je n'ai jamais entendu parler
Delfad0r
1
Btw. il y a une section avec des conseils pour Haskell en particulier où vous pouvez trouver cela et bien d'autres astuces. Oh et il y a toujours aussi des discussions: Of Monads and Men
ბიმო
1

Rétine 0,8,2 , 229 octets

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

Essayez-le en ligne! Je ne sais pas si le format d'E / S est admissible. Explication:

.
$&$&

Dupliquez chaque cellule. La copie de gauche est utilisée comme zone de travail temporaire.

@@
s@

Marquez le début du labyrinthe comme visité.

##
.#

Marquez la fin du labyrinthe comme étant vide.

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

Tant qu'il existe des cellules de travail disponibles, pointez-les vers les cellules adjacentes précédemment visitées.

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

Tracez le chemin de la sortie au début en utilisant les cellules de travail comme guide.

.(.)
$1

Supprimez les cellules de travail.

Neil
la source
1

JavaScript, 450 octets

Prend l'entrée comme (n, {playerx, playery}, {targetx, targety}, [{obstaclex, obstacley}]). Renvoie un tableau 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;}

Voici une version discrète sur mon mess:

// 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
la source