Resolver um labirinto de gelo

19

Labirintos de gelo têm sido um dos meus itens favoritos dos jogos Pokémon desde a sua estreia em Pokémon Gold e Silver. Sua tarefa será criar um programa que resolva esses tipos de problemas.

Labirintos de gelo consistem principalmente, como o nome sugere, em gelo. Uma vez que o jogador se move em uma direção no gelo, ele continuará a se mover nessa direção até colidir com algum obstáculo. Também há solo que pode ser movimentado livremente e impedirá qualquer jogador de se mover. O último obstáculo é a pedra. A pedra não pode ocupar o mesmo espaço que o jogador e, se o jogador tentar entrar nele, parará de se mover antes que possa.

Você receberá um contêiner bidimensional de valores, como uma lista de listas ou uma sequência separada por novas linhas, contendo 3 valores distintos para cada um dos 3 tipos de piso (gelo, solo e pedra). Você também receberá dois pares (ou outros recipientes de valor equivalente) que indicam uma coordenada de início e objetivo no labirinto. Estes podem ser zero ou um indexado.

Você deve produzir uma lista de movimentos (4 valores distintos com uma bijeção em N, E, S, W) que levariam o jogador a chegar ao final quando executado.

A entrada sempre terá um perímetro fechado de pedra ao redor do labirinto, para que você não precise se preocupar com o jogador saindo do labirinto

Isso é então o menor número de bytes vence

Casos de teste

Aqui .representará gelo, ~representará solo e Orepresentará uma pedra. As coordenadas são 1 indexadas. Cada letra da solução representa a direção que começa com essa letra (por exemplo, N= Norte)


Entrada

OOOOO
OO.OO
O...O
OOOOO

Start : 3,3
End   : 3,2

Resultado

N

Entrada

OOOOOOOOOOOOOOOOO
O........O.....OO
O...O..........OO
O.........O....OO
O.O............OO
OO.......O.....OO
O.............OOO
O......O.......~O
O..O...........~O
O.............OOO
O.......O......OO
O.....O...O....OO
O..............OO
OOOOOOOOOOOOOO~~O
OOOOOOOOOOOOOOOOO

Start : 15,12
End   : 16,8

Resultado

N,W,N,E,N,E,S,W,N,W,S,E,S,E,N,E,N

Entrada

OOOOOOOOOOOOOOOO
O~~~~~OOOOO~~~~O
O~~O~OOOOOOO~~OO
O...O..........O
O........O.....O
O..............O
OO.............O
O.............OO
O....~....O....O
O..............O
O..............O
OOOOOOOOOOOOOOOO

Start : 2,2
End   : 14,3

Resultado

E,S,S,W,N,E,N

Entrada

OOOOOOOOOOOOOOOOOOO
O~~~~~~~OOOOOOOOOOO
O~~~~...OOOOOOOOOOO
OO~O~..OOOOOOOOOOOO
O..OO.............O
O..............O..O
O....O............O
O.O............~..O
O........OOOO.....O
O.......OOOOO.....O
O.......O~~~O.....O
O.......~~~~~.....O
O.......~~~~~.....O
O..........O......O
O..O..~...........O
O...............O.O
O.....O...........O
O.................O
OOOOOOOOOOOOOOOOOOO

Start : 2,2
End   : 11,11

Resultado

E,E,E,E,E,S,S,E,N,W,S,E,N,N,N
Assistente de Trigo
fonte
A entrada sempre terá pelo menos uma solução válida?
Pavel
@ Pavel Você pode assumir que sim.
Assistente de trigo
Os casos de teste (linha, coluna) ou (coluna, linha)? 1 ou 0 indexado? As bordas da placa contam como paredes?
MildlyMilquetoast
5
Relacionados
Peter Taylor
2
@busukxuan Você pode ficar permanentemente preso no labirinto (veja a caixa de teste 1)
Assistente de Trigo

Respostas:

4

Mathematica, 247 bytes

(p=x#[[##&@@x]];m={c,v}Switch[p[c+v],0,m[c+v,v],1,c+v,_,c];g=Cases[Array[List,Dimensions@#],c_/;p@c<2,{2}];a=cm[c,#]&/@{{1,0},{-1,0},{0,1},{0,-1}};e=Flatten[Table[#->c,{c,a@#}]&/@g,1];Normalize/@Differences@FindPath[Graph[e],#2,#3][[1]])&

Com quebras de linha:

(
p=x#[[##&@@x]];
m={c,v}Switch[p[c+v],0,m[c+v,v],1,c+v,_,c];
g=Cases[Array[List,Dimensions@#],c_/;p@c<2,{2}];
a=cm[c,#]&/@{{1,0},{-1,0},{0,1},{0,-1}};
e=Flatten[Table[#->c,{c,a@#}]&/@g,1];
Normalize/@Differences@FindPath[Graph[e],#2,#3][[1]]
)&

Minha idéia imediata foi representar as posições de gelo e solo como nós em um gráfico com arestas direcionadas correspondentes a movimentos legais e, em seguida, usar FindPath. Alguém poderia pensar que determinar as medidas legais seria a parte mais fácil e encontrar a solução seria a parte mais difícil. Para mim, foi o contrário. Abra a sugestões sobre como calcular as arestas.

O primeiro argumento #é uma matriz 2D onde 0representa gelo, 1representa solo e 2representa pedra.

O segundo argumento #2e o terceiro argumento #3são os pontos inicial e final, respectivamente, na forma {row,column}.

é o caractere de uso privado de 3 bytes que U+F4A1representa \[Function].

Explicação

p=x#[[##&@@x]];

Define uma função pque obtém uma lista xdo formulário {row,column}e saídas #[[row,column]]; ou seja, o valor de gelo / solo / pedra nessa coordenada.

m={c,v}Switch[p[c+v],0,m[c+v,v],1,c+v,_,c]

Define uma função mque assume um cvetor de posição e direção inicial ve determina recursivamente onde você terminaria. Se c+vé gelo, continuamos deslizando a partir desse ponto, e então ele retorna m[c+v,v]. Se c+vé solo, então nos movemos para c+ve paramos. Caso contrário (se c+vfor pedra ou fora dos limites), você não se mexe. Observe que isso deve ser chamado apenas em posições de gelo ou solo.

g=Cases[Array[List,Dimensions@#],c_/;p@c<2,{2}];

Define a lista gde posições de gelo e solo ( pvalor menor que 2).

a=cm[c,#]&/@{{1,0},{-1,0},{0,1},{0,-1}}; 

Define uma função aque toma uma posição de partida ce retorna o resultado de se mover nos {1,0}, {-1,0}, {0,1}, e {0,-1}instruções. Pode haver alguma redundância. Novamente, isso pressupõe que ccorresponde ao gelo ou ao solo.

e=Flatten[Table[#->c,{c,a@#}]&/@g,1];

Define a lista ede arestas direcionadas que representam movimentos legais. Para cada posição #na g, calcula-se a tabela de arestas #->cpara cada cno a@#. Então, como acabaremos com uma sub-lista para cada posição #, nivelo o primeiro nível. Pode haver alguns loops e várias arestas.

Normalize/@Differences@FindPath[Graph[e],#2,#3][[1]]

Graph[e]é o gráfico em que os nós são as posições legais (gelo ou solo) e as bordas representam movimentos legais (possivelmente colidindo com uma pedra e não se movendo). Em seguida, usamos FindPathpara encontrar um caminho de #2para #3representado como uma lista de nós. Como FindPathpodem ser necessários argumentos adicionais para encontrar mais de um caminho, o resultado será realmente uma lista que contém um único caminho, então eu pego o primeiro elemento usando [[1]]. Então eu tomo o sucessivo Differencesdas coordenadas e Normalizeeles. Assim, cima é {-1,0}, baixo é {1,0}, direita é {0,1}e esquerda é {0,-1}.

Casos de teste

insira a descrição da imagem aqui

insira a descrição da imagem aqui

insira a descrição da imagem aqui

insira a descrição da imagem aqui

insira a descrição da imagem aqui

ngenisis
fonte
4

JavaScript (ES6) 180 183

(m,[x,y],[t,u],o=~m.search`
`,s=[[x-y*o,[]]],k=[])=>eval("for(i=0;[p,l]=s[i++],k[p]=t-u*o-p;)[-1,o,1,-o].map(d=>k[q=(M=p=>+m[p+=d]?m[p]<8?M(p):p:p-d)(p)]||s.push([q,[...l,d]]));l")

Usando um BFS , como fiz para resolver esse desafio relacionado

Entrada
O mapa do labirinto é uma cadeia de linhas múltiplas, usando Oou 0para pedra, 8para o solo e qualquer dígito diferente de zero menor que 8 para gelo ( 7boa aparência).
As posições inicial e final são baseadas em zero.

Saída
Uma lista de deslocamento, onde -1 é W, 1 é E, negativo é menor que -1 Ne positivo positivo é maior que 1.S

Menos golfe

(m,[x,y],[t,u])=>{
  o=~m.search`\n`
  s=[[x-y*o,[]]]
  k=[]
  for(i=0; [p,l]=s[i++], k[p]=1, t-u*o != p;)
  {
    [-1,o,1,-o].map(d=>(
      M=p=>+m[p+=d] ? m[p]<8 ? M(p) : p : p-d,
      q=M(p),
      k[q]||s.push([q,[...l,d]])
    ))
  }
  return l
}

Teste

Solve=
(m,[x,y],[t,u],o=~m.search`
`,s=[[x-y*o,[]]],k=[])=>eval("for(i=0;[p,l]=s[i++],k[p]=t-u*o-p;)[-1,o,1,-o].map(d=>k[q=(M=p=>+m[p+=d]?m[p]<8?M(p):p:p-d)(p)]||s.push([q,[...l,d]]));l")

function Go(maze) {
  var map = maze.textContent;
  var [sx,sy, dx,dy] = map.match(/\d+/g)
  --sx, --sy // zero based
  --dx, --dy // zero based
  map = map.split('\n').slice(1).join('\n') // remove first line
  var result = Solve(map.replace(/\./g, 7).replace(/~/g, 8), [sx,sy], [dx,dy])
  S.textContent = result
  Animate(maze, map, result, sx, sy)
}

function Display(maze, map, pos) {
  var row0 = maze.textContent.split('\n')[0]
  map = [...map]
  map[pos] = '☻'
  maze.textContent = row0+'\n'+map.join('')
}

function Animate(maze, map, moves, x, y) {
  console.log('A',moves)
  var offset = map.search('\n')+1
  var curPos = x + offset * y
  var curMove = 0
  var step = _ => {
    Display(maze, map, curPos)
    if (curMove < moves.length) 
    {
      curPos += moves[curMove]
      if (map[curPos] == 'O')
      {
        curPos -= moves[curMove]
        ++curMove
      }  
      else 
      {
        if (map[curPos] == '~') {
          ++curMove
        }
      }
      setTimeout(step, 100)
    }
    else
      setTimeout(_=>Display(maze,map,-1),500)
  }
  step()
}
td { 
  border: 1px solid #888;
}
Select maze<pre id=S></pre>
<table cellspacing=5><tr>
<td valign=top><input type=radio name=R onclick='Go(M1)'><br>
<pre id=M1>3,3 to 3,2  
OOOOO
OO.OO
O...O
OOOOO</pre></td>
<td valign=top><input type=radio name=R onclick='Go(M2)'><br>
<pre id=M2>15,12 to 16,8
OOOOOOOOOOOOOOOOO
O........O.....OO
O...O..........OO
O.........O....OO
O.O............OO
OO.......O.....OO
O.............OOO
O......O.......~O
O..O...........~O
O.............OOO
O.......O......OO
O.....O...O....OO
O..............OO
OOOOOOOOOOOOOO~~O
OOOOOOOOOOOOOOOOO</pre></td>
<td valign=top><input type=radio name=R onclick='Go(M3)'><br>
<pre id=M3>2,2 to 14,3
OOOOOOOOOOOOOOOO
O~~~~~OOOOO~~~~O
O~~O~OOOOOOO~~OO
O...O..........O
O........O.....O
O..............O
OO.............O
O.............OO
O....~....O....O
O..............O
O..............O
OOOOOOOOOOOOOOOO</pre></td>
<td valign=top><input type=radio name=R onclick='Go(M4)'><br>
<pre id=M4>2,2 to 11,11
OOOOOOOOOOOOOOOOOOO
O~~~~~~~OOOOOOOOOOO
O~~~~...OOOOOOOOOOO
OO~O~..OOOOOOOOOOOO
O..OO.............O
O..............O..O
O....O............O
O.O............~..O
O........OOOO.....O
O.......OOOOO.....O
O.......O~~~O.....O
O.......~~~~~.....O
O.......~~~~~.....O
O..........O......O
O..O..~...........O
O...............O.O
O.....O...........O
O.................O
OOOOOOOOOOOOOOOOOOO</pre></td>
</tr></table>

edc65
fonte