Risolvi un labirinto di ghiaccio


19

I labirinti di ghiaccio sono stati uno dei miei punti preferiti dei giochi Pokémon sin dal loro debutto in Pokémon Oro e Argento. Il tuo compito sarà quello di creare un programma che risolva questo tipo di problemi.

I labirinti di ghiaccio consistono principalmente, come suggerisce il nome, di ghiaccio. Una volta che il giocatore si muove in una direzione sul ghiaccio, continuerà a muoversi in quella direzione fino a quando non si scontrano con qualche ostacolo. C'è anche terreno che può essere spostato liberamente e impedirà a qualsiasi giocatore di attraversarlo. L'ultimo ostacolo è la pietra. La pietra non può occupare lo stesso spazio del giocatore e se il giocatore tenta di entrarci, smetterà di muoversi prima di poterlo fare.

Riceverai un contenitore di valori bidimensionale, come un elenco di elenchi o una stringa separata da newline, contenente 3 valori distinti per ciascuno dei 3 tipi di pavimentazione (Ghiaccio, Suolo e Pietra). Riceverai anche due coppie (o altri contenitori equivalenti a due valori) che indicano un inizio e una coordinata obiettivo nel labirinto. Questi possono essere zero o uno indicizzato.

Devi produrre un elenco di mosse (4 valori distinti con una biiezione su N, E, S, W) che inducono il giocatore ad arrivare alla fine quando viene eseguito.

L'ingresso avrà sempre un perimetro chiuso di pietra attorno al labirinto, quindi non devi preoccuparti del giocatore che esce dal labirinto

Questo è quindi vince il minor numero di byte

Casi test

Qui .rappresenterà il ghiaccio, ~rappresenterà il suolo e Orappresenterà una pietra. Le coordinate sono 1 indicizzate. Ogni lettera nella soluzione rappresenta la direzione che inizia con quella lettera (ad es. N= Nord)


Ingresso

OOOOO
OO.OO
O...O
OOOOO

Start : 3,3
End   : 3,2

Produzione

N

Ingresso

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

Produzione

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

Ingresso

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

Produzione

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

Ingresso

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

Produzione

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

L'input avrà sempre almeno una soluzione valida?
Pavel

@Pavel Puoi crederlo.
Wheat Wizard

I casi di test (riga, colonna) o (colonna, riga)? 1 o 0 indicizzato? I bordi della tavola contano come muri?
MildlyMilquetoast,


2
@busukxuan Puoi rimanere permanentemente intrappolato nel labirinto (vedi testcase 1)
Wheat Wizard

Risposte:


4

Mathematica, 247 byte

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

Con interruzioni di riga:

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

La mia idea immediata era quella di rappresentare le posizioni del ghiaccio e del suolo come nodi in un grafico con bordi diretti corrispondenti alle mosse legali, quindi utilizzare FindPath. Si potrebbe pensare che determinare le mosse legali sarebbe la parte facile e trovare la soluzione sarebbe la parte difficile. Per me era il contrario. Apri suggerimenti su come calcolare i bordi.

Il primo argomento #è un array 2D in cui 0rappresenta il ghiaccio,1 rappresenta il suolo e 2rappresenta la pietra.

Il secondo argomento #2e il terzo argomento #3sono i punti iniziale e finale, rispettivamente, nella forma{row,column} .

è il carattere di uso privato a 3 byte che U+F4A1rappresenta\[Function] .

Spiegazione

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

Definisce una funzione pche accetta un elenco xdi forma {row,column}e output #[[row,column]]; cioè, il valore di ghiaccio / suolo / pietra a quella coordinata.

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

Definisce una funzione mche prende una posizione iniziale ce un vettore di direzione ve determina ricorsivamente dove andresti a finire. Se c+vè ghiaccio, continuiamo a scivolare da quel punto, quindi ritorna m[c+v,v]. Se c+vè terreno, allora ci spostiamo c+ve ci fermiamo. Altrimenti (se c+vè di pietra o fuori limite), non ti muovi. Si noti che questo è destinato solo per essere chiamato su posizioni di ghiaccio o suolo.

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

Definisce l'elenco gdelle posizioni del ghiaccio e del suolo ( pvalore inferiore a 2).

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

Definisce una funzione ache prende una posizione di partenza ce restituisce i risultati del movimento nelle {1,0}, {-1,0}, {0,1}, e {0,-1}le direzioni. Potrebbe esserci un po 'di ridondanza. Ancora una volta, ciò presuppone che ccorrisponda al ghiaccio o al suolo.

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

Definisce l'elenco edei bordi diretti che rappresentano le mosse legali. Per ogni posizione #in g, calcolare la tabella dei bordi #->cper ciascuno cin a@#. Quindi, poiché finiremo con un elenco secondario per ogni posizione #, appiattisco il primo livello. Potrebbero esserci alcuni loop e bordi multipli.

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

Graph[e]è il grafico in cui i nodi sono le posizioni legali (ghiaccio o suolo) e i bordi rappresentano mosse legali (possibilmente sbattere contro una pietra e non muoversi). Usiamo quindi FindPathper trovare un percorso da #2a #3rappresentato come un elenco di nodi. Dal momento che FindPathpuò prendere argomenti aggiuntivi per trovare più di un percorso, il risultato sarà in realtà un elenco contenente un singolo percorso, quindi prendo il primo elemento utilizzando [[1]]. Quindi prendo il successivo Differencesdelle coordinate e Normalizeloro. Quindi su è {-1,0}, giù è {1,0}, destra è {0,1}e sinistra è {0,-1}.

Casi test

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine


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 un BFS , come ho fatto per risolvere questa sfida correlata

Input
La mappa del labirinto è una stringa multilinea, che usa Oo 0per la pietra, 8per il suolo e qualsiasi cifra diversa da zero per 8 per il ghiaccio ( 7aspetto buono).
Le posizioni iniziale e finale sono basate su zero.

Output
Un elenco di offset, dove -1 è W, 1 è E, negativo minore di -1 è Ne positivo maggiore di 1 èS

Meno golf

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

Test

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>

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.