Tire-me daqui

12

Desafio

Dado o tamanho da grade, as posições dos obstáculos, a posição do jogador e a posição do alvo, sua tarefa é encontrar um caminho para o jogador chegar ao alvo e evitar os obstáculos ao mesmo tempo (se necessário).

insira a descrição da imagem aqui


Entrada

  • N : tamanho da gradeN x N
  • P : Posição do jogador[playerposx, playerposy]
  • T : Posição do alvo[targetposx, targetposy]
  • O : Posições dos obstáculos[[x1, y1], [x2, y2],...,[xn, yn]]

Resultado

Caminho : um jogador do caminho pode usar para alcançar o alvo[[x1, y1], [x2, y2],...,[xn, yn]]


Regras

  1. O ponto [0,0]está no canto superior esquerdo da grade.
  2. A posição do jogador sempre estará no lado esquerdo da grade.
  3. A posição do alvo sempre estará no lado direito da grade.
  4. A grade sempre terá pelo menos um obstáculo.
  5. Você pode assumir que nenhum obstáculo se sobrepõe à posição do jogador ou do alvo.
  6. Você não precisa necessariamente encontrar o caminho mínimo.
  7. O jogador só pode se mover para a esquerda, direita, superior e inferior, não na diagonal.
  8. Você pode receber a entrada de qualquer maneira conveniente.
  9. Você pode assumir que sempre existirá um caminho para o jogador chegar ao alvo.
  10. Obviamente, para cada entrada existem vários caminhos válidos, escolha um.
  11. Suponha N > 2que a grade seja pelo menos 3 x 3.

Exemplos

Entrada: 9, [6, 0], [3, 8], [[0, 5], [2, 2], [6, 4], [8, 2], [8, 7]]
saída possível:[[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]]
saída possível:[[1, 0], [1, 1], [2, 1], [2, 2], [2, 3], [2, 4], [3, 4], [3, 5]]


Nota

Observe que Xé para linhas e Ypara colunas . Não os confunda com as coordenadas da imagem.

Editar

Como @digEmAll apontou, devido às regras #2e #3, playerY = 0e targetY = N-1. Então, se você quiser, pode tomar como única entrada playerXe e targetX(se isso faz seu código mais curto).

DimChtz
fonte
1
"A posição do jogador estará sempre no lado esquerdo e o alvo no lado direito": isso significa que o jogador-y = 0 e o alvo-y = N-1? Nesse caso, podemos simplesmente aceitar a coordenada x (um número) para o jogador e o alvo?
precisa saber é o seguinte
1
@digEmAll Bom ponto. Honestamente, eu não pensei nisso e sim, você pode editar isso.
DimChtz
Relacionado, mas mais fácil. Relacionado, mas mais difícil.
User202729
O caminho precisa ser do início ao fim ou pode estar na ordem inversa?
Kamoroso94 01/09/19
1
@ kamoroso94 Sim, começar a alvejar (acabamento) :)
DimChtz

Respostas:

5

JavaScript (ES6), 135 bytes

Assume a entrada como (width, [target_x, target_y], obstacles)(source_x, source_y), onde obstáculos é uma matriz de seqüências de caracteres em "X,Y"formato.

Retorna uma matriz de seqüências de caracteres no "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

Experimente online!

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

Experimente online!

Não é muito curto e definitivamente não está fornecendo o caminho mais curto (por exemplo, verifique o primeiro exemplo).
Ele basicamente executa uma pesquisa recursiva em profundidade e pára assim que o alvo é atingido, imprimindo o caminho.

Agradecimentos a JayCe pela melhoria na formatação da saída

digEmAll
fonte
1 Eu gosto da maneira que você imprimir a saída (não a lista chato típico de listas) :)
DimChtz
@DimChtz: bem obrigado, mas ... essa é a função auxiliar, a função de código-golf apenas imprime uma lista de coordenadas x1 y1 x2 y2 ... xn yn: D
digEmAll
1
Sim, eu sei: P, mas ainda agradável.
DimChtz 01/09/19
1
Concordo com @DimChtz ... e eu acho que parece ainda melhor se write(t(mx),1,N), em vez de printing :)
Jayce
@ JayCe: boa ideia, mudou!
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]

Experimente online!

ovs
fonte
3

Haskell , 133 131 130 bytes

  • -1 byte graças 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])

Experimente online! (com alguns casos de teste)

Uma função que !toma como entrada

  • n :: Int tamanho da grade
  • p :: [Int] posição do jogador como uma lista [xp, yp]
  • o :: [[Int]] posição dos obstáculos como uma lista [[x1, y1], [x2, y2], ...]
  • t :: [[[Int]]](implícita) posição do alvo como uma lista [[[xt, yt]]](lista tripla apenas por conveniência)

e retornando um caminho válido como uma lista [[xp, yp], [x1, y1], ..., [xt, yt]].

Como bônus, ele encontra (um dos) caminhos mais curtos e funciona para a posição de qualquer jogador e alvo. Por outro lado, é muito ineficiente (mas os exemplos fornecidos são executados em um período de tempo razoável).

Explicação

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

A expressão aparentemente obscura [id, map (+ 1)] <*> [[x - 1,y], [x, y - 1]]é apenas uma versão "golfy" (-1 byte) de [[x + 1, y], [x, y + 1], [x - 1, y], [x, y - 1]].

Delfad0r
fonte
2
Bem-vindo ao PPCG! Boa primeira resposta!
Arnauld
1
@ Arnauld Thanks! Na verdade, eu passei várias horas tentando espremer alguns bytes para fora da minha solução justa para bater o seu 135 ^^
Delfad0r
1
Bom golfe! Você pode salvar um byte usando um operador em vez de uma função: Experimente online!
ბიმო
@ BWO Obrigado pela dica. Eu sou novo aqui, por isso há muitos truques que eu nunca ouvi falar
Delfad0r
1
Btw. uma seção com dicas para Haskell, em particular, onde você pode encontrar isso e muitos outros truques. Ah, e sempre há bate-papo também: Of Monads and Men
#
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

Experimente online! Não tenho certeza se o formato de E / S está qualificado. Explicação:

.
$&$&

Duplique cada célula. A cópia esquerda é usada como uma área de trabalho temporária.

@@
s@

Marque o início do labirinto como visitado.

##
.#

Marque o final do labirinto como vazio.

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

Enquanto existirem células de trabalho disponíveis, aponte-as para células adjacentes visitadas anteriormente.

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

Rastreie o caminho desde a saída até o início usando as células em funcionamento como um guia.

.(.)
$1

Exclua as células de trabalho.

Neil
fonte
1

JavaScript, 450 bytes

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

Aqui está uma versão não ofuscada na minha bagunça:

// 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
fonte