Corredores assustadores

8

Este desafio é inspirado em um jogo de tabuleiro que joguei há algum tempo.
A história desse desafio não precisa necessariamente ser lida; o objetivo da seção de desafio deve explicar tudo o que é necessário.

A história

As pessoas estão trancadas dentro de uma grande sala com um monstro devorador de seres humanos. As paredes da sala estão encantadas, teleportando objetos pela sala quando tocadas. O referido monstro marcha pelo quarto, procurando carne. O primeiro humano à sua vista será consumido por seus dentes afiados.

O objetivo do desafio

Você recebe o mapa da sala, incluindo a localização das pessoas e do monstro.

%%%KLMNOPQRSTA%
%%J           B
%I       %    C
H             D
G   %%        E
F             F
E      %      G
D             H
C   %        I%
B           J%%
%ATSRQPONMLK%%%

Vamos dividir os componentes do mapa.

  • Cartas de Apara T: Se o monstro pisar em uma delas, ele será teleportado para a segunda aparição dessa carta e não mudará de direção. Só haverá zero ou duas letras no quadro.
  • %: Revestimento de parede. Apenas para formatação e boa aparência.
  • #: A localização inicial do monstro.
  • *: A localização das pessoas.
  •  : Peças vazias, o monstro pode se mover livremente sobre elas.

Algumas coisas adicionais a serem observadas sobre o mapa:

  • As dimensões do mapa e a localização do objeto não serão constantes; portanto, seu código precisará se adaptar dinamicamente a isso.

O monstro sempre seguirá na direção em que está atualmente (voltado para o oeste no início), a menos que encontre um humano; nesse caso, ele se volta para o humano mais próximo .
O monstro avista um humano se não houver azulejos de parede ou teletransportador em uma linha horizontal ou vertical reta entre ele e o humano.

Outra coisa a se notar é que, se o monstro estiver na frente de uma parede sólida ( %) ou precisar decidir entre dois humanos, ele sempre priorizará da direita para a esquerda.

Se o monstro não conseguir virar à direita e dar um passo à frente por algum motivo, ele virará à esquerda .

Então, no final, a ordem em que o monstro prioriza as direções encaminhamos, direita, esquerda, para trás.

Entrada

  • O mapa, incluindo a localização inicial do monstro e as posições das pessoas como seus respectivos personagens. Não deve haver outra entrada além da sequência do mapa, ou a matriz de sequências ou caracteres.

A entrada pode ser recebida em qualquer formato razoável; uma única sequência ou uma matriz de sequências para o mapa.

Resultado

A coordenada da pessoa que primeiro é comida pelo monstro.

As coordenadas começam no canto superior esquerdo e são indexadas em 0; portanto, o primeiro bloco terá as coordenadas (0 | 0). Se você estiver usando a indexação 1, especifique-a na sua resposta.

Regras

  • Este é o , o código mais curto em bytes em qualquer idioma vence.
  • As brechas padrão são proibidas.
  • Você pode assumir que o monstro sempre será capaz de alcançar um humano.

Casos de teste

Entrada:

%%%KLMNOPQRSTA%
%%J           B
%I       %*   C
H   *         D
G   %%        E
F       #     F
E      %      G
D      *      H
C   %        I%
B           J%%
%ATSRQPONMLK%%%

Saída: (10,2)como o monstro não pode ver as outras duas pessoas quando passa por elas, é teleportado para a outra Fparede, onde verá a última pessoa.

Entrada:

%%%KLMNOPQRSTA%
%%J           B
%I      *     C
H     %%%   * D
G      #%     E
F     %%%   % F
E             G
D       %     H
C       *    I%
B       *   J%%
%ATSRQPONMLK%%%

Resultado: (12,3)

Entrada:

%%%KLMNOPQRSTA%
%%J           B
%I     %%%    C
H     *%#%    D
G             E
F             F
E       %     G
D             H
C            I%
B           J%%
%ATSRQPONMLK%%%

Resultado: (6, 3)

Entrada:

%%%%%%%%%%%%%%%
%#%       %%% %
%A%ABCD   %*% %
%*F     G %%% %
% %BC% FD     %
% %   %    %%%%
% %  %       %%
%   % %%   G  %
%             %
%*%    %    % %
%%%%%%%%%%%%%%%

Resultado: (1,9)


Boa sorte!

Ian H.
fonte
Você deve declarar, explicitamente e no início da descrição, que os humanos não se movem. Eu não percebi a princípio que eles são estacionários. Se eu fosse humano nessa situação, certamente estaria me mexendo!
DLosc 28/09

Respostas:

6

Python 2 , 565 .. 422 445 1 .. 444 463 2 .. 468 467 463 bytes

u,U='*%'
G=lambda s:u==s.strip('# ')[0]and len(N)-s.find(u)
b=input()
D=3;j=''.join;N,w,P,t,B=j(b),len(b[0]),[0,1,0,-1],{},map(j,zip(*b))
for c in N:
 l,r=N.find(c),N.rfind(c)
 if u<c:t[l]=r;t[r]=l
 if'#'==c:x,y=l%w,l/w
while u!=b[y][x]:
 O=[B[x][y-1::-1],b[y][x+1:],B[x][y+1:],b[y][x-1::-1]];L,R=O[D-1],O[~D]
 if u<b[y][x]:X=t[x+w*y];x,y=X%w,X/w
 elif(G(O[D])<1)*(G(R)+G(L)+(U==O[D][0])):D-=0<G(L)>G(R)or(U==R[0])*-~(U==L[0])or-1;D%=4
 x+=P[D];y+=P[~D]
print x,y

Experimente online!

Economizou muitos bytes graças a Halvard , Ian e Jonathan

1: Tem mais tempo, a fim de corrigir o caso de virar duas vezes e encontrar a localização do monstro.
2: Ficou ainda mais tempo. O monstro não deve mudar de direção ao se teletransportar.

TFeld
fonte
Um pouco jogou para 482 bytes . Link encurtado devido ao fato de o TIO ser muito demorado
Halvard Hummel
@Halvard Um pequeno golfe, apenas 1 byte: 481
1
l.replace('#',' ')-> l.replace(*"# ").
Jonathan Frech 27/09
Fixo, mas agora é o mesmo comprimento que o seu, 434 bytes
2
@KevinCruijssen Eu sei que Ian disse que minha resposta conta como válida, mas vou mudar de qualquer maneira.
TFeld
5

Perl 6 ,343 334 333 328 322 308 bytes

{my \m=%((^@^a X ^@a[0]).map:{.[0]i+.[1]=>@a[.[0]][.[1]]});my \a=m<>:k.classify
({m{$_}});my$m=a<#>[0];my$d=-1;{$d=($d,i*$d,-i*$d,-$d).min({$^q;first ?*,map
{(((my \u=m{$m+$_*$q})~~"%")*(1+!($_-1))+(u~~"A".."Z"))*m+(u~~"*")*$_},^m});
$m+=$d;$m=$d+(a{m{$m}}∖~$m).pick while m{$m}~~"A".."Z"}...{m{$m}~~"*"};$m}

Experimente online!

(Não há novas linhas no código real. Eu as inseri apenas para quebrar as linhas para facilitar a leitura.)

Não é possível lidar com mapas onde é possível ver fora dos limites do mapa. (Ou seja, mapeia com espaços vazios na borda.) Se isso importa, +5 bytes. Mas, como os teleportadores bloqueiam o LoS ​​agora, não deveriam.

Explicação : É uma função que leva o mapa como uma lista de listas de caracteres. Vamos dividir em declarações:

my \m=%((^@^a X ^@a[0]).map:{.[0]i+.[1]=>@a[.[0]][.[1]]});: Vamos criar um hash ("dicionário" para Pythonists) chamado m(é uma variável sem sinal, portanto, precisamos ser explícitos sobre a atribuição de um hash %(...)) que associa chaves complexas de forma x+iya caracteres que estão nas colunas th ye thown xdo mapa.

my \a=m<>:k.classify({m{$_}});: Isso cria um "dicionário inverso" de m, chamado a: existe uma chave correspondente a cada valor em me o valor é uma lista de coordenadas complexas (entradas m) que contêm esse caractere. Assim, por exemplo, a{"#"}será apresentada uma lista de todas as coordenadas em que há uma #no mapa. (Essa também é uma variável sem sinal, mas estamos com sorte, pois classifyretorna um hash.)

my$m=a<#>[0];my$d=-1: Defina a posição inicial do monstro. Procuramos #o hash inverso a. Devemos usar, [0]pois a<#>ainda é uma lista, mesmo quando contém apenas 1 elemento. O $dcontém a direção do monstro; colocamos no oeste. (A direção também é um número complexo, assim -1como o oeste.)

OK, a próxima afirmação é bastante desagradável. Primeiro, vamos dar uma olhada no seguinte: {$^q;first ?*,map {(((my$u=m{my$t=$m+$_*$q})~~"%")*(1+!($_-1))+($u~~"A".."Z"))*m+($u~~"*")*abs($t-$m)},^m}Esta é uma rotina que avalia LoS na direção especificada. Se houver um humano nessa direção, ele retornará a distância para o humano. Se houver uma parede ou um teleporte nessa direção, ele retornará o número total de quadrados do mapa. (O objetivo é fornecer um número tão alto que seja maior que qualquer distância legítima de um humano.) Finalmente, se a parede estiver nessa direção e na distância 1, retornamos 2 × o número total de quadrados do mapa. (Como nunca queremos correr pelas paredes, elas precisam de uma pontuação ainda maior. Escolheremos o mínimo em breve.)

Nós usamos isso na construção $d=($d,i*$d,-i*$d,-$d).min( LoS deciding block );. Como usamos números complexos para tudo, podemos obter facilmente direções que são relativas para a frente, direita, esquerda e para trás a partir da direção original apenas multiplicando-a por 1, i, -i (lembre-se de que o yeixo segue o outro caminho que você pode usado para matemática) e -1, respectivamente. Então, formamos a lista de direções nessa ordem e encontramos a direção que tem a mínima "distância até um humano" (de acordo com o bloco acima), o que garante que qualquer humano bata em qualquer parede e qualquer coisa que bata em uma parede que seja correta sob o nariz do monstro. Usamos o fato de que a minfunção fornece o primeirovalor mínimo. Se houver um empate na distância entre várias direções, o monstro preferirá avançar da direita para a esquerda para trás, o que é exatamente o que queremos. Então, temos uma nova direção que é então atribuída $d.

$m+=$d; apenas faz o monstro pisar na nova direção.

$m=$d+(a{m{$m}}∖~$m).pick while m{$m}~~"A".."Z"cuida dos teleports. Digamos que o monstro esteja em um teletransporte A. Primeiro, procuramos Ano hash inverso %ae isso aumenta as duas posições do teletransporte A, depois descartamos a posição atual usando o operador de diferença definida (que parece uma barra invertida). Como existem exatamente 2 ocorrências de cada teleporte no mapa e o monstro certamente está de pé em uma, a diferença será um conjunto com 1 elemento. Em seguida, usamos .pickpara escolher um elemento aleatório (acredite ou não, mas esta é a maneira mais curta de obter o elemento do conjunto de 1 elemento :—)). Esse tipo de coisa acontece até que o monstro acaba em algum lugar que não está em um portal.

Tudo nos últimos 4 parágrafos descreve uma construção maciça de forma {change direction; step; handle teleports}...{m{$m}~~"*"}. Esta é uma sequência que chama o bloco à esquerda de ...até que a condição à direita da ...seja verdadeira. E isso é verdade quando o monstro está em um quadrado com um humano. A própria lista contém valores de retorno do bloco enorme à esquerda, que é lixo (provavelmente (Any)) porque retorna o valor do loop while no final. Essencialmente, nós o usamos como um loop while mais barato. O valor da lista é descartado (e o compilador geme sobre um "uso inútil de ...um concurso de afundamento", mas quem se importa). Quando tudo estiver pronto, retornamos $m- a posição do monstro depois que ele encontrou um humano, ainda como um número complexo (então, para o primeiro teste, damos 10+2ie assim por diante).

Ramillies
fonte
Boa explicação! :)
Ian H.
3

JavaScript (ES6), 258 245

g=>eval("m=g[I='indexOf']`#`,D=[w=g[I]`\n`+1,-1,-w,k=t=1],g=[...g];for(n=1/0;n;(o=g[m+=d=D[k]])>'@'?g[g[u=m]=t=1,m=g[I](o),u]=o:o<'%'?t=1:o<'*'&&(m-=d,k=k+t++&3))D.map((d,j)=>{for(q=0,u=m;g[u+=d]<'%';++q);g[u]=='*'&n>q&&(n=q,k=j)});[m%w,m/w|0]")

Menos golfe

g=>{
    var u, // temp current position 
        q, // distance so far scanning for a human
        o, // value of grid at current position
        d, // offset to move given current direction
        n = 1/0 // current distance from human
        m = g.indexOf(`#`), // monster position
        w = g.indexOf(`\n`)+1, // grid width + 1 (offset to next row)
        D = [w,-1,-w,1], // offset for moves, clockwise
        k = 1, // current direction, start going west
        t = 1; // displacement for turn
    g=[...g]; // string to array
    while (n) // repeat while not found (distance > 0)
    {
      // look around to find humans
      D.forEach( (d,j) => { // for each direction
        // scan grid to find a human
        for(q=0, u=m; g[u+=d]<'$'; ++q); // loop while blank space
        if ( g[u] == '*' // human found at position u
             & n>q ) // and at a shorter distance than current
        {
           n = q; // remember min distance
           k = j; // set current direction
        }
      })
      // if human found, the current direction is changed accordingly
      d = D[k] // get delta
      m += d // move
      o = g[m] // current cell in o
      if (o > '@') // check if letter (teleporter)
      {
        t = 1 // keep current direction, next turn will be right
        u = m // save current position in u
        g[u] = 1 // clear current cell, so I can find only the other teleporter
        m = g.indexOf(o) // set current position to other teleporter
        g[u] = o // reset previous cell content
      }
      else if (o > '%') // check if '*'
      {
        // set result, so we can exit the loop
        r = [ m%w, m/w|0 ] // x and y position 
      }
      else if (o == '%') // check if wall
      {
        // turn
        m -= d // current position invalid, go back
        k = (k+t) % 4 // turn right 90° * t
        t = t+1 // next turn will be wider
      }
      else
      {
        t = 1 // keep current direction, next turn will be right
      }
    }
    return r
}

Teste

var F=
g=>eval("m=g[I='indexOf']`#`,D=[w=g[I]`\n`+1,-1,-w,k=t=1],g=[...g];for(n=1/0;n;(o=g[m+=d=D[k]])>'@'?g[g[u=m]=t=1,m=g[I](o),u]=o:o<'%'?t=1:o<'*'&&(m-=d,k=k+t++&3))D.map((d,j)=>{for(q=0,u=m;g[u+=d]<'%';++q);g[u]=='*'&n>q&&(n=q,k=j)});[m%w,m/w|0]")

var grid=[`%%%KLMNOPQRSTA%\n%%J           B\n%I       %*   C\nH   *         D\nG   %%        E\nF       #     F\nE      %      G\nD      *      H\nC   %        I%\nB           J%%\n%ATSRQPONMLK%%%`
,'%%%KLMNOPQRSTA%\n%%J           B\n%I      *     C\nH     %%%   * D\nG      #%     E\nF     %%%   % F\nE             G\nD       %     H\nC       *    I%\nB       *   J%%\n%ATSRQPONMLK%%%'
,'%%%KLMNOPQRSTA%\n%%J           B\n%I     %%%    C\nH     *%#%    D\nG             E\nF             F\nE       %     G\nD             H\nC            I%\nB           J%%\n%ATSRQPONMLK%%%'
,'%%%%%%%%%%%%%%%\n%#%       %%% %\n%A%ABCD   %*% %\n%*F     G %%% %\n% %BC% FD     %\n% %   %    %%%%\n% %  %       %%\n%   % %%   G  %\n%             %\n%*%    %    % %\n%%%%%%%%%%%%%%%'
]
$(function(){
  var $tr = $('tr')
  grid.forEach(x=>{
    $tr.eq(0).append("<td>"+x+"</td>")
    $tr.eq(1).append("<td>"+F(x)+"</td>")
  })
})
td {padding: 4px; border: 1px solid #000; white-space:pre; font-family:monospace }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table ><tr/><tr/></table>

edc65
fonte